GT-3409 MDMang MD5-hashed symbols

This commit is contained in:
ghizard 2019-12-18 13:03:11 -05:00
parent 9ad7c6843f
commit 1c1cd58eb9
6 changed files with 241 additions and 45 deletions

View File

@ -480,6 +480,17 @@ public class MDMang {
public MDObjectCPP getEmbeddedObject(MDObjectCPP obj) {
return obj;
}
/**
* This method is meant to be overridden as needed to process a hashed
* object. In this default case (MDMang), we properly process the
* hashed object. Overridden methods might just throw an exception,
* allowing a failed demangling.
*/
public void processHashedObject(MDObjectCPP obj) throws MDException {
obj.processHashedObject();
}
}
/******************************************************************************/

View File

@ -46,10 +46,6 @@ public class MDMangGhidra extends MDMang {
return dataTypeResult;
}
private DemangledType processNamespace(MDQualifiedBasicName qualifiedBasicName) {
return processNamespace(qualifiedBasicName.getQualification());
}
public DemangledType processNamespace(MDQualifiedName qualifiedName) {
return processNamespace(qualifiedName.getQualification());
}
@ -183,8 +179,8 @@ public class MDMangGhidra extends MDMang {
}
else {
variable = new DemangledVariable(
objectCPP.getQualifiedName().getBasicName().toString());
variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
}
variable.setDatatype(dt);
resultObject = variable;
@ -204,8 +200,8 @@ public class MDMangGhidra extends MDMang {
}
else if (typeinfo instanceof MDFunctionInfo) {
DemangledFunction function =
new DemangledFunction(objectCPP.getQualifiedName().getBasicName().toString());
function.setNamespace(processNamespace(objectCPP.getQualifiedName()));
new DemangledFunction(objectCPP.getName());
function.setNamespace(processNamespace(objectCPP.getQualfication()));
resultObject = function;
objectResult = processFunction((MDFunctionInfo) typeinfo, function);
// Any other special values to be set?
@ -233,8 +229,8 @@ public class MDMangGhidra extends MDMang {
else if (typeinfo instanceof MDVxTable) { //Includes VFTable, VBTable, and RTTI4
MDVxTable vxtable = (MDVxTable) typeinfo;
DemangledVariable variable =
new DemangledVariable(objectCPP.getQualifiedName().getBasicName().toString());
variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
new DemangledVariable(objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
variable.setConst(vxtable.isConst());
variable.setVolatile(vxtable.isVolatile());
variable.setPointer64(vxtable.isPointer64());
@ -245,8 +241,8 @@ public class MDMangGhidra extends MDMang {
}
else if (typeinfo instanceof AbstractMDMetaClass) { //Includes all RTTI, except RTTI4
DemangledVariable variable =
new DemangledVariable(objectCPP.getQualifiedName().getBasicName().toString());
variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
new DemangledVariable(objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
resultObject = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
@ -254,8 +250,8 @@ public class MDMangGhidra extends MDMang {
}
else if (typeinfo instanceof MDGuard) {
DemangledVariable variable =
new DemangledVariable(objectCPP.getQualifiedName().getBasicName().toString());
variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
new DemangledVariable(objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
resultObject = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
@ -264,8 +260,8 @@ public class MDMangGhidra extends MDMang {
else {
// Any others (e.g., case '9')
DemangledVariable variable =
new DemangledVariable(objectCPP.getQualifiedName().getBasicName().toString());
variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
new DemangledVariable(objectCPP.getName());
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
resultObject = variable;
// The following code would be an alternative, depending on whether we get
// customer complaints or other fall-out from having created a variable here.
@ -288,9 +284,9 @@ public class MDMangGhidra extends MDMang {
}
}
else {
String baseName = objectCPP.getQualifiedName().getBasicName().toString();
if (objectCPP.getQualifiedName().isString()) {
MDString mstring = objectCPP.getQualifiedName().getBasicName().getMDString();
String baseName = objectCPP.getName();
if (objectCPP.isString()) {
MDString mstring = objectCPP.getMDString();
DemangledString demangledString = new DemangledString(mstring.getName(),
mstring.toString(), mstring.getLength(), mstring.isUnicode());
resultObject = demangledString;
@ -298,7 +294,7 @@ public class MDMangGhidra extends MDMang {
else if (baseName.length() != 0) {
DemangledVariable variable;
variable = new DemangledVariable(baseName);
variable.setNamespace(processNamespace(objectCPP.getQualifiedName()));
variable.setNamespace(processNamespace(objectCPP.getQualfication()));
resultObject = variable;
}
}
@ -803,13 +799,10 @@ public class MDMangGhidra extends MDMang {
@Override
public MDObjectCPP getEmbeddedObject(MDObjectCPP obj) {
MDObjectCPP embedded = obj.getQualifiedName().getBasicName().getEmbeddedObject();
if (embedded != null) {
return embedded;
}
return obj;
return obj.getEmbeddedObject();
}
}
/******************************************************************************/
/******************************************************************************/

View File

@ -111,6 +111,12 @@ public class MDMangVS2015 extends MDMang {
public MDObjectCPP getEmbeddedObject(MDObjectCPP obj) {
return obj.getEmbeddedObject();
}
@Override
public void processHashedObject(MDObjectCPP obj) throws MDException {
obj.processHashedObjectMSVC();
}
}
/******************************************************************************/

View File

@ -61,6 +61,10 @@ public class MDQualifiedBasicName extends MDParsableItem {
return -1;
}
/**
* Returns {@code true} if the symbol's Basic Name is of a {@link MDString} type.
* @return {@code true} if Basic Name is of {@link MDString} type.
*/
public boolean isString() {
if (basicName == null) {
return false;
@ -68,6 +72,18 @@ public class MDQualifiedBasicName extends MDParsableItem {
return basicName.isString();
}
/**
* Returns the {@link MDString} from the Basic Name if it is a symbol of that type; else
* returns null.
* @return the {@link MDString} or null if does not exist.
*/
public MDString getMDString() {
if (isString()) {
return basicName.getMDString();
}
return null;
}
@Override
public void insert(StringBuilder builder) {
basicName.insert(builder);

View File

@ -15,10 +15,8 @@
*/
package mdemangler.object;
import mdemangler.MDException;
import mdemangler.MDMang;
import mdemangler.naming.MDBasicName;
import mdemangler.naming.MDQualifiedBasicName;
import mdemangler.*;
import mdemangler.naming.*;
import mdemangler.typeinfo.MDTypeInfo;
import mdemangler.typeinfo.MDTypeInfoParser;
@ -26,9 +24,11 @@ import mdemangler.typeinfo.MDTypeInfoParser;
* This class represents a derivative of an <b><code>MDObject</code></b> which is a C++ object.
*/
public class MDObjectCPP extends MDObject {
protected MDHashedObject hashedObject;
protected MDQualifiedBasicName qualifiedName;
protected MDTypeInfo typeInfo;
protected boolean embeddedObjectFlag;
protected boolean hashedObjectFlag;
public MDObjectCPP(MDMang dmang) {
super(dmang);
@ -49,16 +49,66 @@ public class MDObjectCPP extends MDObject {
*/
public MDObjectCPP getEmbeddedObject() {
if (embeddedObjectFlag) {
return getQualifiedName().getBasicName().getEmbeddedObject();
return qualifiedName.getBasicName().getEmbeddedObject();
}
return this;
}
/**
* Returns the name of the symbol, minus any namespace component.
* @return the name.
*/
public String getName() {
if (hashedObjectFlag) {
return hashedObject.toString();
}
return getQualifiedName().getBasicName().toString();
}
/**
* Returns the {@link MDQualification} component that represents the namespace.
* @return the namespace information.
*/
public MDQualification getQualfication() {
if (hashedObjectFlag) {
return hashedObject.getQualification();
}
return getQualifiedName().getQualification();
}
/**
* Returns {@code true} if the symbol's Basic Name is of a {@link MDString} type.
* @return {@code true} if Basic Name is of {@link MDString} type.
*/
public boolean isString() {
if (qualifiedName == null) {
return false;
}
return qualifiedName.isString();
}
/**
* Returns the {@link MDString} from the Basic Name if it is a symbol of that type; else
* returns null.
* @return the {@link MDString} or null if does not exist.
*/
public MDString getMDString() {
if (isString()) {
return qualifiedName.getMDString();
}
return null;
}
@Override
public void insert(StringBuilder builder) {
qualifiedName.insert(builder);
if (typeInfo != null) {
typeInfo.insert(builder);
if (hashedObjectFlag) {
hashedObject.insert(builder);
}
else {
qualifiedName.insert(builder);
if (typeInfo != null) {
typeInfo.insert(builder);
}
}
}
@ -71,23 +121,123 @@ public class MDObjectCPP extends MDObject {
if ((dmang.peek(0) == '?') && (dmang.peek(1) == '?')) { //??? prefix
embeddedObjectFlag = true;
}
qualifiedName = new MDQualifiedBasicName(dmang);
qualifiedName.parse();
if (qualifiedName.isString()) {
return;
if ((dmang.peek(0) == '?') && (dmang.peek(1) == '@')) { //??@ prefix
// MDMANG SPECIALIZATION USED.
dmang.processHashedObject(this);
}
if (dmang.peek() != MDMang.DONE) {
int RTTINum = qualifiedName.getRTTINumber();
typeInfo = MDTypeInfoParser.parse(dmang, RTTINum);
if (qualifiedName.isTypeCast()) {
typeInfo.setTypeCast();
else {
qualifiedName = new MDQualifiedBasicName(dmang);
qualifiedName.parse();
if (qualifiedName.isString()) {
return;
}
typeInfo.parse();
if (!typeInfo.getNameModifier().isEmpty()) {
qualifiedName.setNameModifier(typeInfo.getNameModifier());
if (dmang.peek() != MDMang.DONE) {
int RTTINum = qualifiedName.getRTTINumber();
typeInfo = MDTypeInfoParser.parse(dmang, RTTINum);
if (qualifiedName.isTypeCast()) {
typeInfo.setTypeCast();
}
typeInfo.parse();
if (!typeInfo.getNameModifier().isEmpty()) {
qualifiedName.setNameModifier(typeInfo.getNameModifier());
}
}
}
}
public void processHashedObject() throws MDException {
hashedObject = new MDHashedObject(dmang);
hashedObject.parse();
hashedObjectFlag = true;
}
public void processHashedObjectMSVC() throws MDException {
throw new MDException("cannot parse hashed symbol");
}
/**
* Represents the MD5 hashed representation of the internals of the {@link MDObjectCPP}.
* It takes the place of the {@link MDQualifiedBasicName}. We have included an unused
* (except to be able to return one that is empty) {@link MDQualification} so that the
* {@link MDObjectCPP} has one to return.
* <p>
* Not sure that we will keep this class in the long run or find a way to include it
* inside of the {@link MDObjectCPP} or if this {@link MDHashedObject} should be pulled
* out separately and detected/parsed by the {@link MDMangObjectParser}. If this last
* thing is done, then we would have to find places in the package where we explicitly
* create {@link MDObjectCPP MDObjectCPPs}, such as in {@link MDNestedName}, and check to
* see if we can modify those locations (in all cases) to perform the detecting/parsing
* using the {@link MDMangObjectParser}. This will need more study when more time is
* available.
*/
public class MDHashedObject extends MDParsableItem {
private String hashString = "";
private MDQualification qualification; // We are making this dummy object
/**
* Constructor for {@link MDHashedObject}
* @param dmang The {@link MDMang} for which the work is performed and from from which
* the information is parsed.
*/
public MDHashedObject(MDMang dmang) {
super(dmang);
qualification = new MDQualification(dmang);
}
/**
* Returns the hashed string.
* @return the hashed string.
*/
public String getHashString() {
return hashString;
}
/**
* Returns an empty {@link MDQualification} that represents the namespace of the symbol.
* Note: we have yet to decide whether we should do anything but this.
* @return the namespace information (empty for now).
*/
public MDQualification getQualification() {
return qualification;
}
@Override
protected void parseInternal() throws MDException {
if ((dmang.peek() != '?') && (dmang.peek(1) != '@')) {
throw new MDException("Invalid HashedObject");
}
dmang.increment(2);
StringBuilder builder = new StringBuilder();
char ch;
int start = dmang.getIndex();
while ((ch = dmang.peek()) != MDMang.DONE) {
if (ch == '@') {
break;
}
if (!(Character.isLetter(ch) || Character.isDigit(ch))) {
break;
}
builder.append(ch);
dmang.next();
}
int end = dmang.getIndex();
if ((end - start) != 32 || ch != '@') {
throw new MDException("Invalid HashedObject");
}
dmang.increment();
hashString = builder.toString();
}
@Override
public void insert(StringBuilder builder) {
// We have made up the output format. Nothing is sacrosanct about this output.
builder.append("`" + hashString + "'");
}
}
}
/******************************************************************************/

View File

@ -14472,6 +14472,26 @@ public class MDMangBaseTest extends AbstractGenericTest {
demangleAndTest();
}
//Issue 1344: Long symbols get MD5-hashed.
// We have made up the output format. Nothing is sacrosanct about this output.
@Test
public void testHashedSymbolComponentsLongerThan5096_1() throws Exception {
mangled = "??@f4873c94f485cd6716c2319fc51ac714@";
msTruth = "";
mdTruth = "`f4873c94f485cd6716c2319fc51ac714'";
demangleAndTest();
}
//Issue 1344: Long symbols get MD5-hashed.
// We have made up the output format. Nothing is sacrosanct about this output.
@Test
public void testHashedSymbolComponentsLongerThan5096_2() throws Exception {
mangled = "?catch$0@?0???@f4873c94f485cd6716c2319fc51ac714@@4HA";
msTruth = "";
mdTruth = "int ``f4873c94f485cd6716c2319fc51ac714''::`1'::catch$0";
demangleAndTest();
}
//TODO: ignore for now.
@Ignore
public void testFuzzyFit() throws Exception {