Merge remote-tracking branch

'origin/GP-656_jmlagor_Process_pointers,_function_pointers,_mark_up_valuetypes_and_custommods--SQUASHED'

Conflicts:
	Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/pe/cli/streams/CliStreamMetadata.java
This commit is contained in:
ghidra1
2021-03-17 18:46:11 -04:00
11 changed files with 671 additions and 221 deletions

View File

@@ -4,9 +4,9 @@
* 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.
@@ -107,12 +107,12 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
ELEMENT_TYPE_VALUETYPE(0x11),
ELEMENT_TYPE_VAR(0x13), // "Class type variable VAR"
(0x16),
ELEMENT_TYPE_MVAR(0x1e), // Method type variable MVAR
ELEMENT_TYPE_INTERNAL(0x21), // Internal (generated internally, "will not be persisted in any way")
ELEMENT_TYPE_MAX(0x22),
*/
switch (typeCode) {
@@ -431,32 +431,95 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
}
public class CliTypeFnPtr extends CliSigType {
private CliAbstractSig sig;
private boolean isDefSig; // true => MethodDef, false => MethodRef
private long dataOffset;
private CliRetType retType;
private CliParam params[];
private int sizeOfCount;
private byte flags;
private int genericParamCount;
private int sizeOfGenericCount;
private int sentinelIndex; // SENTINEL is before the parameter index in this field
private final int FNPTR_FLAGS_DEFAULT = 0x00;
private final int FNPTR_FLAGS_VARARG = 0x05;
private final int FNPTR_FLAGS_GENERIC = 0x10;
private final int FNPTR_FLAGS_HASTHIS = 0x20;
private final int FNPTR_FLAGS_EXPLICITTHIS = 0x40;
public CliTypeFnPtr(BinaryReader reader, CliElementType typeCode) throws IOException {
super(typeCode);
// TODO: MethodDef and MethodRef sig need to have static isX(reader) methods so I can tell the difference
//sig = new CliSigMethodRef(blob); // MethodRef is just Def plus possible sentinel and minus potential XORed args in the first byte
sentinelIndex = -1;
dataOffset = reader.getPointerIndex();
// Flags is similar to a MethodDef unless vararg is used.
flags = reader.readNextByte();
if ((flags & FNPTR_FLAGS_GENERIC) == FNPTR_FLAGS_GENERIC) {
long origIndex = reader.getPointerIndex();
genericParamCount = decodeCompressedUnsignedInt(reader);
sizeOfGenericCount = (int) (reader.getPointerIndex() - origIndex);
}
long origIndex = reader.getPointerIndex();
int paramCount = decodeCompressedUnsignedInt(reader);
this.sizeOfCount = (int) (reader.getPointerIndex() - origIndex);
try {
retType = new CliRetType(reader);
}
catch (InvalidInputException e) {
retType = null;
}
params = new CliParam[paramCount];
for (int i = 0; i < paramCount; i++) {
if (reader.peekNextByte() == CliElementType.ELEMENT_TYPE_SENTINEL.id()) {
reader.readNextByte();
sentinelIndex = i;
}
try {
params[i] = new CliParam(reader);
}
catch (InvalidInputException e) {
params[i] = null;
}
}
}
@Override
public String getRepresentation() {
return "FnPtr " + sig.getRepresentation();
return "FnPtr " /*+ sig.getRepresentation()*/;
}
@Override
public String getShortRepresentation() {
return "FnPtr " + sig.getShortRepresentation();
return "FnPtr " /*+ sig.getShortRepresentation()*/;
}
@Override
public DataType getDefinitionDataType() {
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), "FnPtr", 0);
struct.add(CliTypeCodeDataType.dataType, "FnPtr", "FnPtr");
struct.add(DWORD, "MethodDefOrRef", "index into blob heap");
StructureDataType struct =
new StructureDataType(new CategoryPath(PATH), "FnPtr_" + dataOffset, 0);
struct.add(CliTypeCodeDataType.dataType, CliElementType.ELEMENT_TYPE_FNPTR.toString(),
"");
struct.add(BYTE, "Flags", "ORed VARARG/GENERIC/HASTHIS/EXPLICITTHIS");
if (genericParamCount > 0) {
struct.add(getDataTypeForBytes(sizeOfGenericCount), "GenParamCount",
"Number of generic paramameters for the method");
}
struct.add(getDataTypeForBytes(sizeOfCount), "ParamCount",
"Number of parameter types to follow RetType");
struct.add(retType.getDefinitionDataType(), "RetType", null);
for (int i = 0; i < params.length; i++) {
struct.add(params[i].getDefinitionDataType(), "Param" + i, null);
}
return struct;
// TODO: Return the correct size of a signature reference (always 4B in this context perchance?)
}
}
@@ -552,17 +615,18 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
}
public class CliTypeVarOrMvar extends CliSigType {
private long dataOffset;
private int number;
private int numberBytes;
public CliTypeVarOrMvar(BinaryReader reader, CliElementType typeCode) throws IOException {
super(typeCode);
long origIndex = reader.getPointerIndex();
dataOffset = reader.getPointerIndex();
number = decodeCompressedUnsignedInt(reader);
long endIndex = reader.getPointerIndex();
numberBytes = (int) (endIndex - origIndex);
numberBytes = (int) (endIndex - dataOffset);
}
@Override
@@ -572,9 +636,9 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
@Override
public DataType getDefinitionDataType() {
StructureDataType struct =
new StructureDataType(new CategoryPath(PATH), "VarOrMvar", 0);
struct.add(BYTE, "Type", "Var or Mvar");
StructureDataType struct = new StructureDataType(new CategoryPath(PATH),
baseTypeCode.toString() + "_" + dataOffset, 0);
struct.add(CliTypeCodeDataType.dataType, baseTypeCode.toString(), "");
struct.add(getDataTypeForBytes(numberBytes), "number", null);
return struct;
}
@@ -582,16 +646,24 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
public class CliTypePtr extends CliSigType {
private List<CliCustomMod> customMods = new ArrayList<>();
private CliElementType typeCode;
private CliSigType type;
private long dataOffset;
public CliTypePtr(BinaryReader reader, CliElementType typeCode) throws IOException {
public CliTypePtr(BinaryReader reader, CliElementType typeCode)
throws IOException, InvalidInputException {
super(typeCode);
dataOffset = reader.getPointerIndex();
while (CliCustomMod.isCustomMod(reader)) {
customMods.add(new CliCustomMod(reader));
}
typeCode = CliElementType.fromInt(reader.readNextByte());
type = readCliType(reader);
}
public CliSigType getType() {
return type;
}
@Override
@@ -601,17 +673,22 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
modsRep += mod.toString() + ", ";
}
modsRep = modsRep.substring(0, modsRep.length() - 2);
return String.format("Ptr %s %s", modsRep, typeCode.toString());
return String.format("Ptr %s %s", modsRep, type.toString());
}
@Override
public DataType getDefinitionDataType() {
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), "Ptr", 0);
struct.add(CliTypeCodeDataType.dataType, "TypeCode", "Ptr");
StructureDataType struct = new StructureDataType(new CategoryPath(PATH),
CliElementType.ELEMENT_TYPE_PTR.toString() + "_" + dataOffset, 0);
struct.add(CliTypeCodeDataType.dataType, CliElementType.ELEMENT_TYPE_PTR.toString(),
"");
for (CliCustomMod mod : customMods) {
struct.add(mod.getDefinitionDataType());
}
struct.add(CliTypeCodeDataType.dataType, "Type", "type or void");
struct.add(type.getDefinitionDataType(), type.baseTypeCode.toString(), "");
return struct;
}
}
@@ -682,6 +759,19 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
typeBytes = (int) (endIndex - origIndex);
}
public CliTypeTable getTable() {
try {
return CliIndexTypeDefOrRef.getTableName(encodedType);
}
catch (InvalidInputException e) {
return null;
}
}
public int getRowIndex() {
return CliIndexTypeDefOrRef.getRowIndex(encodedType);
}
@Override
public String getRepresentation() {
return "ValueType " + Integer.toHexString(encodedType);
@@ -714,12 +804,17 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
@Override
public DataType getDefinitionDataType() {
String tableName = getTable().name();
StructureDataType struct =
new StructureDataType(new CategoryPath(PATH), "ValueType", 0);
struct.add(CliTypeCodeDataType.dataType, "ValueType", "ValueType");
struct.add(getDataTypeForBytes(typeBytes), "Type", "TypeDefOrRefOrSpecEncoded");
struct.add(getDataTypeForBytes(typeBytes), "TypeDefOrRefEncoded",
tableName + ": Row 0x" + Integer.toHexString(getRowIndex()));
return struct;
}
}
public CliSigType readCliType(BinaryReader reader) throws IOException, InvalidInputException {
@@ -761,10 +856,11 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
}
}
// The CustomMod signature part contains a required CMOD option (CMOD_OPT or CMOD_REQD) then a compressed TypeDefOrRefOrSpecEncoded
public static class CliCustomMod {
// The CustomMod signature part contains a required CMOD
// option (CMOD_OPT or CMOD_REQD) then a compressed TypeDefOrRefOrSpecEncoded
public static class CliCustomMod implements CliRepresentable {
private CliElementType cmod;
private int typeEncoded;
private int encodedType;
private int sizeOfCount;
public static boolean isCustomMod(BinaryReader reader) throws IOException {
@@ -776,7 +872,7 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
cmod = CliElementType.fromInt(reader.readNextByte());
long origIndex = reader.getPointerIndex();
typeEncoded = decodeCompressedUnsignedInt(reader);
encodedType = decodeCompressedUnsignedInt(reader);
long endIndex = reader.getPointerIndex();
sizeOfCount = (int) (endIndex - origIndex);
@@ -787,12 +883,12 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
}
public int getTypeEncoded() {
return typeEncoded;
return encodedType;
}
public CliTypeTable getTable() {
try {
return CliIndexTypeDefOrRef.getTableName(typeEncoded);
return CliIndexTypeDefOrRef.getTableName(encodedType);
}
catch (InvalidInputException e) {
return null;
@@ -800,7 +896,7 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
}
public int getRowIndex() {
return CliIndexTypeDefOrRef.getRowIndex(typeEncoded);
return CliIndexTypeDefOrRef.getRowIndex(encodedType);
}
public CliAbstractTableRow getRow(CliStreamMetadata stream) {
@@ -808,25 +904,40 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
}
public DataType getDefinitionDataType() {
StructureDataType struct = new StructureDataType(new CategoryPath(PATH),
CliCustomMod.class.getSimpleName(), 0);
struct.add(BYTE, "CMOD", "CMOD_OPT or CMOD_REQD");
struct.add(getDataTypeForBytes(this.sizeOfCount), "Type",
"TypeDefOrRefOrSpec encoded type");
StructureDataType struct =
new StructureDataType(new CategoryPath(PATH), "CustomMod", 0);
String tableName = getTable().name();
struct.add(CliTypeCodeDataType.dataType, cmod.toString(), null);
struct.add(getDataTypeForBytes(this.sizeOfCount), "TypeDefOrRefEncoded",
tableName + ": Row 0x" + Integer.toHexString(getRowIndex()));
return struct;
}
@Override
public String getRepresentation(CliStreamMetadata stream) {
return String.format("%s %s", cmod.toString(), getRow(stream));
}
@Override
public String getRepresentation() {
return String.format("%s %x", cmod.toString(), typeEncoded);
return String.format("%s %x", cmod.toString(), encodedType);
}
@Override
public String getShortRepresentation() {
return getRepresentation();
}
@Override
public String getShortRepresentation(CliStreamMetadata stream) {
return getRepresentation(stream);
}
}
// The only possible constraint is ELEMENT_TYPE_PINNED (CliTypeCode.Pinned)
public static class CliConstraint {
public static class CliConstraint implements CliRepresentable {
private CliElementType constraint;
public static boolean isConstraint(BinaryReader reader) throws IOException {
@@ -841,6 +952,7 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
return constraint;
}
@Override
public String getRepresentation() {
if (constraint == CliElementType.ELEMENT_TYPE_PINNED) {
return constraint.toString();
@@ -848,36 +960,96 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
return String.format("Invalid Constraint (%s - %x)", constraint.toString(),
constraint.id());
}
@Override
public String getShortRepresentation() {
return getRepresentation();
}
@Override
public String getRepresentation(CliStreamMetadata stream) {
return getRepresentation();
}
@Override
public String getShortRepresentation(CliStreamMetadata stream) {
return getRepresentation();
}
}
// The only possible result is ELEMENT_TYPE_BYREF
public static class CliByRef implements CliRepresentable {
private CliElementType byRef;
public static boolean isByRef(BinaryReader reader) throws IOException {
return (reader.peekNextByte() == CliElementType.ELEMENT_TYPE_BYREF.id());
}
public CliByRef(BinaryReader reader) throws IOException {
byRef = CliElementType.fromInt(reader.readNextByte());
}
public CliElementType getByRef() {
return byRef;
}
@Override
public String getRepresentation() {
if (byRef == CliElementType.ELEMENT_TYPE_BYREF) {
return byRef.toString();
}
return String.format("Invalid ByRef (%s - %x)", byRef.toString(), byRef.id());
}
@Override
public String getShortRepresentation() {
return getRepresentation();
}
@Override
public String getRepresentation(CliStreamMetadata stream) {
return getRepresentation();
}
@Override
public String getShortRepresentation(CliStreamMetadata stream) {
return getRepresentation();
}
}
public class CliTypeBase implements CliRepresentable {
private List<CliCustomMod> customMods = new ArrayList<>();
private boolean constraint = false;
private boolean byRef = false;
private List<CliRepresentable> modifiers = new ArrayList<>();
private CliSigType type;
private long dataOffset = 0;
private boolean isVoidAllowed = false;
public CliTypeBase(BinaryReader reader, boolean isRetType)
throws IOException, InvalidInputException {
dataOffset = reader.getPointerIndex();
this.isVoidAllowed = isRetType;
// Get any custom modifiers
while (CliCustomMod.isCustomMod(reader)) {
customMods.add(new CliCustomMod(reader));
}
// Check for any of the modifiers, which can repeat out of order
// before encountering the base type
while (CliCustomMod.isCustomMod(reader) || CliConstraint.isConstraint(reader) ||
CliByRef.isByRef(reader)) {
// Check to see if it's a constrained variable
if (CliConstraint.isConstraint(reader)) {
constraint = true;
reader.readNextByte();
}
// Get any custom modifiers
while (CliCustomMod.isCustomMod(reader)) {
modifiers.add(new CliCustomMod(reader));
}
// Check to see if it's a ByRef
byte byRefCheck = reader.peekNextByte();
if (byRefCheck == CliElementType.ELEMENT_TYPE_BYREF.id()) {
byRef = true;
reader.readNextByte();
// Check to see if it's a constrained variable
if (CliConstraint.isConstraint(reader)) {
modifiers.add(new CliConstraint(reader));
}
// Check to see if it's a ByRef
if (CliByRef.isByRef(reader)) {
modifiers.add(new CliByRef(reader));
}
}
type = readCliType(reader);
@@ -888,34 +1060,48 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
}
public List<CliCustomMod> getCustomMods() {
List<CliCustomMod> customMods = new ArrayList<CliCustomMod>();
for (CliRepresentable mod : modifiers) {
if (mod instanceof CliCustomMod) {
customMods.add((CliCustomMod) mod);
}
}
return customMods;
}
public boolean isByRef() {
return byRef;
for (CliRepresentable mod : modifiers) {
if (mod instanceof CliByRef) {
return true;
}
}
return false;
}
public boolean isConstrained() {
return constraint;
for (CliRepresentable mod : modifiers) {
if (mod instanceof CliConstraint) {
return true;
}
}
return false;
}
private String getRepresentationCommon(CliStreamMetadata stream, boolean shortRep) {
String rep = "";
for (CliCustomMod mod : customMods) {
rep += mod.getRepresentation() + "; ";
}
if (customMods.size() > 0) {
rep = rep.substring(0, rep.length() - 2) + " ";
}
if (constraint) {
rep += "constrained ";
}
if (byRef) {
rep += "byref ";
for (CliRepresentable mod : modifiers) {
if (mod instanceof CliCustomMod) {
CliCustomMod customMod = (CliCustomMod) mod;
rep += customMod.getRepresentation() + "; ";
}
else if (mod instanceof CliConstraint) {
rep += "constrained ";
}
else if (mod instanceof CliByRef) {
rep += "byref ";
}
}
// The one special case value we have is the SENTINEL, which
@@ -952,20 +1138,25 @@ public abstract class CliAbstractSig extends CliBlob implements CliRepresentable
}
public DataType getDefinitionDataType() {
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), "Type", 0);
StructureDataType struct =
new StructureDataType(new CategoryPath(PATH), "Type_" + dataOffset, 0);
for (CliCustomMod mod : customMods) {
struct.add(mod.getDefinitionDataType(), "CustomMod", null);
for (CliRepresentable mod : modifiers) {
if (mod instanceof CliCustomMod) {
CliCustomMod customMod = (CliCustomMod) mod;
struct.add(customMod.getDefinitionDataType(), "CustomMod", null);
}
else if (mod instanceof CliConstraint) {
struct.add(CliTypeCodeDataType.dataType,
CliElementType.ELEMENT_TYPE_PINNED.toString(), "Constrained");
}
else if (mod instanceof CliByRef) {
struct.add(CliTypeCodeDataType.dataType,
CliElementType.ELEMENT_TYPE_BYREF.toString(), "By Reference");
}
}
if (constraint) {
struct.add(BYTE, "CONSTRAINT", "Constrained");
}
if (byRef) {
struct.add(BYTE, "BYREF", "By reference");
}
struct.add(type.getDefinitionDataType(), "Type", null);
struct.add(type.getDefinitionDataType(), type.baseTypeCode.toString(), null);
return struct;
}

View File

@@ -26,12 +26,14 @@ import ghidra.util.exception.InvalidInputException;
public class CliSigField extends CliAbstractSig {
private CliParam type;
private long dataOffset;
private static final byte CLISIGFIELD_PROLOG = 0x06;
public CliSigField(CliBlob blob) throws IOException {
super(blob);
BinaryReader reader = getContentsReader();
dataOffset = reader.getPointerIndex();
byte prolog = reader.readNextByte();
if (prolog != CLISIGFIELD_PROLOG) {
@@ -67,7 +69,7 @@ public class CliSigField extends CliAbstractSig {
public DataType getContentsDataType() {
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), getName(), 0);
struct.add(BYTE, "FIELD", "Magic (0x06)");
struct.add(type.getDefinitionDataType(), "Type", null);
struct.add(type.getDefinitionDataType(), type.getType().baseTypeCode.toString(), null);
return struct;
}

View File

@@ -85,17 +85,19 @@ public class CliSigMethodDef extends CliAbstractSig {
@Override
public DataType getContentsDataType() {
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), getName(), 0);
struct.add(BYTE, "flags", "ORed calling convention and THIS presence"); // TODO: enum
struct.add(BYTE, "Flags", "ORed VARARG/GENERIC/HASTHIS/EXPLICITTHIS"); // TODO: enum
if (genericParamCount > 0) {
struct.add(getDataTypeForBytes(sizeOfGenericCount), "GenParamCount",
"Number of generic paramameters for the method");
}
struct.add(getDataTypeForBytes(sizeOfCount), "Count",
"Number of param types to follow RetType");
"Number of parameter types to follow RetType");
struct.add(retType.getDefinitionDataType(), "RetType", null);
for (CliParam param : params) {
struct.add(param.getDefinitionDataType(), null, null);
for (int i = 0; i < params.length; i++) {
struct.add(params[i].getDefinitionDataType(), "Param" + i, null);
}
return struct;
}

View File

@@ -23,7 +23,7 @@ import ghidra.program.model.data.*;
import ghidra.util.exception.InvalidInputException;
public class CliSigMethodRef extends CliAbstractSig {
private long dataOffset;
private CliRetType retType;
private CliParam params[];
private int sizeOfCount;
@@ -45,6 +45,8 @@ public class CliSigMethodRef extends CliAbstractSig {
// Flags is similar to a MethodDef unless vararg is used.
BinaryReader reader = getContentsReader();
dataOffset = reader.getPointerIndex();
flags = reader.readNextByte();
if ((flags & METHODREFSIG_FLAGS_GENERIC) == METHODREFSIG_FLAGS_GENERIC) {
@@ -90,16 +92,21 @@ public class CliSigMethodRef extends CliAbstractSig {
@Override
public DataType getContentsDataType() {
StructureDataType struct = new StructureDataType(new CategoryPath(PATH), getName(), 0);
struct.add(BYTE, "FirstByte", "ORed VARARG and HASTHIS/EXPLICITTHIS");
struct.add(BYTE, "Flags", "ORed VARARG/GENERIC/HASTHIS/EXPLICITTHIS");
if (genericParamCount > 0) {
struct.add(getDataTypeForBytes(sizeOfGenericCount), "GenParamCount",
"Number of generic paramameters for the method");
}
struct.add(getDataTypeForBytes(sizeOfCount), "ParamCount",
"Number of param types to follow RetType");
"Number of parameter types to follow RetType");
struct.add(retType.getDefinitionDataType(), "RetType", null);
for (int i = 0; i < params.length; i++) {
struct.add(params[i].getDefinitionDataType(), "Type" + i, null);
if (sentinelIndex == i) {
struct.add(CliTypeCodeDataType.dataType,
CliElementType.ELEMENT_TYPE_SENTINEL.toString(), "SENTINEL");
}
struct.add(params[i].getDefinitionDataType(), "Param" + i, null);
}
return struct;
}

View File

@@ -4,9 +4,9 @@
* 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.
@@ -24,69 +24,81 @@ import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
public class CliMethodDef implements StructConverter {
public static final String PATH = "/PE/CLI/Methods/MethodDefs";
private Address addr;
private boolean isFatHeader;
private boolean hasMoreSections;
private boolean initLocals;
public enum HeaderFormat {
Fat, Tiny
}
private int headerFlags;
private HeaderFormat headerFormat;
private int headerSize; // Size of this header
private int maxStack; // Max number of items on operand stack
private int methodSize; // Size of method body (code)
private int localVarSigTok;
private static final int CLIMETHODDEF_HEADER_FLAGS_SHIFT = 0x08;
private static final int CLIMETHODDEF_HEADER_FLAGS_MASK = 0x0FFF;
private static final int CLIMETHODDEF_HEADER_SIZE_SHIFT = 0x0C;
private static final int CLIMETHODDEF_HEADER_SIZE_FAT_MULTIPLIER = 0x04;
private static final byte CorILMethod_TinyFormat = 0x2;
private static final byte CorILMethod_FatFormat = 0x3;
private static final byte CorILMethod_MoreSects = 0x8;
private static final byte CorILMethod_InitLocals = 0x10;
public CliMethodDef(Address addr, BinaryReader reader) throws IOException {
this.addr = addr;
// Read first byte, see if tiny or fat.
byte one = reader.readNextByte();
if ((one & CorILMethod_FatFormat) == CorILMethod_FatFormat) {
isFatHeader = true;
if ((one & CorILMethod_MoreSects) == CorILMethod_MoreSects)
hasMoreSections = true;
if ((one & CorILMethod_InitLocals) == CorILMethod_InitLocals)
initLocals = true;
byte two = reader.readNextByte(); // TODO: need to read byte two? Seems to only have header length (in the wrong order?? >_<)
int firstByte = reader.readNextUnsignedByte();
if ((firstByte & CorILMethod_FatFormat) == CorILMethod_FatFormat) {
headerFormat = HeaderFormat.Fat;
// The header flags are stored across 12 bits, the top 4 bits
// indicate the size of the header
headerFlags =
(firstByte << CLIMETHODDEF_HEADER_FLAGS_SHIFT) + reader.readNextUnsignedByte();
headerSize = headerFlags >> CLIMETHODDEF_HEADER_SIZE_SHIFT;
headerFlags = (headerFlags & CLIMETHODDEF_HEADER_FLAGS_MASK);
// The raw header size bits indicate: "Size of this header
// expressed as the count of 4-bytes integers occupied."
headerSize = headerSize * CLIMETHODDEF_HEADER_SIZE_FAT_MULTIPLIER;
maxStack = reader.readNextShort();
methodSize = reader.readNextInt();
localVarSigTok = reader.readNextInt();
}
else if ((one & CorILMethod_TinyFormat) == CorILMethod_TinyFormat) {
isFatHeader = false;
hasMoreSections = false;
initLocals = false;
else if ((firstByte & CorILMethod_TinyFormat) == CorILMethod_TinyFormat) {
headerFormat = HeaderFormat.Tiny;
headerSize = 1;
headerFlags = 0;
maxStack = 8;
methodSize = (((one & ~0x3) & 0xff) >> 2); // Mask off first 2 bits, right shift to get 6 length bits. 0xff mask to convert to right sign.
methodSize = (((firstByte & ~0x3) & 0xff) >> 2); // Mask off first 2 bits, right shift to get 6 length bits. 0xff mask to convert to right sign.
}
}
private void fillTinyHeaderType(Structure struct) {
struct.add(BYTE, "Size+Flags", "L.S. Bits 0:1 Flags, Bits 2:7 Size of method in Bytes");
}
private void fillFatHeaderType(Structure struct) {
struct.add( WORD, "Size+Flags", "L.S. Bits 0:3 Size of hdr in B, Bits 4:15 Flags");
struct.add( WORD, "MaxStack", "Maximum number of items on the operand stack");
struct.add(DWORD, "CodeSize", "Size of actual method body in B");
struct.add(DWORD, "LocalVarSigTok", "Signature for the local variables of the method. 0 means no locals. References standalone signature in Metadata tables, which references #Blob heap.");
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
StructureDataType struct =
new StructureDataType(new CategoryPath(PATH), "MethodDefHdr_" + addr, 0);
if (isFatHeader) {
fillFatHeaderType(struct);
StructureDataType struct;
if (headerFormat == HeaderFormat.Fat) {
struct = new StructureDataType(new CategoryPath(PATH), "MethodDefHdr_Fat", 0);
struct.add(WORD, "Size+Flags", "L.S. Bits 0:3 Size of hdr in bytes, Bits 4:15 Flags");
struct.add(WORD, "MaxStack", "Maximum number of items on the operand stack");
struct.add(DWORD, "CodeSize", "Size of actual method body in bytes");
struct.add(DWORD, "LocalVarSigTok",
"Signature for the local variables of the method. 0 means no locals. References standalone signature in Metadata tables, which references #Blob heap.");
}
else {
fillTinyHeaderType(struct);
struct = new StructureDataType(new CategoryPath(PATH), "MethodDefHdr_Tiny", 0);
struct.add(BYTE, "Size+Flags", "L.S. Bits 0:1 Flags, Bits 2:7 Size of method in Bytes");
}
return struct;
}
@@ -95,7 +107,14 @@ public class CliMethodDef implements StructConverter {
}
public boolean hasMoreSections() {
return hasMoreSections;
return (headerFlags & CorILMethod_MoreSects) == CorILMethod_MoreSects;
}
public boolean hasLocals() {
return (headerFlags & CorILMethod_InitLocals) == CorILMethod_InitLocals;
}
public HeaderFormat getHeaderFormat() {
return headerFormat;
}
}

View File

@@ -4,9 +4,9 @@
* 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.

View File

@@ -35,7 +35,7 @@ import ghidra.util.task.TaskMonitor;
/**
* The Metadata stream is giant and complicated. It is made up of {@link CliAbstractTable}s.
*
*
* @see CliTypeTable
*/
public class CliStreamMetadata extends CliAbstractStream {
@@ -55,7 +55,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the name of this stream.
*
*
* @return The name of this stream.
*/
public static String getName() {
@@ -64,13 +64,13 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Creates a new Metadata stream.
*
*
* @param header The stream header associated with this stream.
* @param guidStream The GUID stream.
* @param userStringsStream The user strings stream.
* @param stringsStream The strings stream.
* @param blobStream The blob stream.
* @param fileOffset The file offset where this stream starts.
* @param fileOffset The file offset where this stream starts.
* @param rva The relative virtual address where this stream starts.
* @param reader A reader that is set to the start of the stream.
* @throws IOException if there is a problem reading the stream.
@@ -133,7 +133,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the GUID stream.
*
*
* @return The GUID stream. Could be null if one doesn't exist.
*/
public CliStreamGuid getGuidStream() {
@@ -142,7 +142,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the user strings stream.
*
*
* @return The user strings stream. Could be null if one doesn't exist.
*/
public CliStreamUserStrings getUserStringsStream() {
@@ -151,7 +151,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the strings stream.
*
*
* @return The strings stream. Could be null if one doesn't exist.
*/
public CliStreamStrings getStringsStream() {
@@ -160,7 +160,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the blob stream.
*
*
* @return The blob stream. Could be null if one doesn't exist.
*/
public CliStreamBlob getBlobStream() {
@@ -170,7 +170,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Creates a new {@link CliAbstractTable} from the table at the current reader index
* with the given table type.
*
*
* @param tableType The type of table to create.
* @return A new table with the given type. Could be null if we don't support the table type.
* @throws IOException if there was an issue reading the new table.
@@ -300,7 +300,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the major version.
*
*
* @return The major version.
*/
public short getMajorVersion() {
@@ -309,7 +309,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the minor version.
*
*
* @return The minor version.
*/
public short getMinorVersion() {
@@ -318,7 +318,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the sorted field.
*
*
* @return The sorted field.
*/
public long getSorted() {
@@ -327,7 +327,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the valid field.
*
*
* @return The valid field.
*/
public long getValid() {
@@ -336,7 +336,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the table with the provided table type from the metadata stream.
*
*
* @param tableType The type of table to get.
* @return The table with the provided table type. Could be null if it doesn't exist.
*/
@@ -360,7 +360,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the table with the provided table type id from the metadata stream.
*
*
* @param tableId The id of the table type to get.
* @return The table with the provided table id. Could be null if it doesn't exist.
*/
@@ -370,9 +370,9 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the number of rows in the table with the given table type.
*
*
* @param tableType The type of table to get the number of rows of.
* @return The number of rows in the table with the given table type. Could be 0 if
* @return The number of rows in the table with the given table type. Could be 0 if
* the table of the given type was not found.
*/
public int getNumberRowsForTable(CliTypeTable tableType) {
@@ -383,7 +383,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the data type of the index into the string stream. Will be either
* {@link DWordDataType} or {@link WordDataType}.
*
*
* @return The data type of the index into the string stream.
*/
public DataType getStringIndexDataType() {
@@ -393,7 +393,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the data type of the index into the GUID stream. Will be either
* {@link DWordDataType} or {@link WordDataType}.
*
*
* @return The data type of the index into the string stream.
*/
public DataType getGuidIndexDataType() {
@@ -403,7 +403,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the data type of the index into the Blob stream. Will be either
* {@link DWordDataType} or {@link WordDataType}.
*
*
* @return The data type of the index into the string stream.
*/
public DataType getBlobIndexDataType() {
@@ -413,7 +413,7 @@ public class CliStreamMetadata extends CliAbstractStream {
/**
* Gets the data type of the index into a metadata table. Will be either
* {@link DWordDataType} or {@link WordDataType}.
*
*
* @return The data type of the index into the string stream.
*/
public DataType getTableIndexDataType(CliTypeTable table) {
@@ -435,7 +435,7 @@ public class CliStreamMetadata extends CliAbstractStream {
table.markup(program, isBinary, monitor, log, ntHeader);
}
catch (Exception e) {
Msg.error(this, "Failed to markup " + table + ": " + e.toString());
Msg.error(this, "Failed to markup " + table + ": " + e.getMessage());
}
}
}

View File

@@ -30,6 +30,7 @@ import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.listing.Program;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
@@ -100,16 +101,24 @@ public class CliTableField extends CliAbstractTable {
public void markup(Program program, boolean isBinary, TaskMonitor monitor, MessageLog log,
NTHeader ntHeader)
throws DuplicateNameException, CodeUnitInsertionException, IOException {
int fieldRowIndex = 0;
for (CliAbstractTableRow row : rows) {
CliFieldRow fieldRow = (CliFieldRow) row;
fieldRowIndex++;
// Create FieldSig object and bookmark it
// Create FieldSig object
Address sigAddr = CliAbstractStream.getStreamMarkupAddress(program, isBinary, monitor,
log, ntHeader, metadataStream.getBlobStream(), fieldRow.sigIndex);
CliSigField fieldSig =
new CliSigField(metadataStream.getBlobStream().getBlob(fieldRow.sigIndex));
metadataStream.getBlobStream().updateBlob(fieldSig, sigAddr, program);
if (!metadataStream.getBlobStream().updateBlob(fieldSig, sigAddr, program)) {
Msg.warn(CliTableField.class,
"Couldn't update FieldSig blob " +
metadataStream.getStringsStream().getString(fieldRow.nameIndex) +
" at Field table index " + fieldRowIndex);
}
}
}

View File

@@ -4,9 +4,9 @@
* 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.
@@ -16,14 +16,13 @@
package ghidra.app.util.bin.format.pe.cli.tables;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.*;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.MemoryByteProvider;
import ghidra.app.util.bin.format.pe.NTHeader;
import ghidra.app.util.bin.format.pe.PeUtils;
import ghidra.app.util.bin.format.pe.cli.blobs.CliAbstractSig.CliParam;
import ghidra.app.util.bin.format.pe.cli.blobs.CliAbstractSig.*;
import ghidra.app.util.bin.format.pe.cli.blobs.CliBlob;
import ghidra.app.util.bin.format.pe.cli.blobs.CliSigMethodDef;
import ghidra.app.util.bin.format.pe.cli.methods.CliMethodDef;
@@ -31,6 +30,8 @@ import ghidra.app.util.bin.format.pe.cli.methods.CliMethodExtraSections;
import ghidra.app.util.bin.format.pe.cli.streams.CliAbstractStream;
import ghidra.app.util.bin.format.pe.cli.streams.CliStreamMetadata;
import ghidra.app.util.bin.format.pe.cli.tables.CliTableParam.CliParamRow;
import ghidra.app.util.bin.format.pe.cli.tables.CliTableTypeDef.CliTypeDefRow;
import ghidra.app.util.bin.format.pe.cli.tables.CliTableTypeRef.CliTypeRefRow;
import ghidra.app.util.bin.format.pe.cli.tables.flags.CliFlags.CliEnumMethodAttributes;
import ghidra.app.util.bin.format.pe.cli.tables.flags.CliFlags.CliEnumMethodImplAttributes;
import ghidra.app.util.importer.MessageLog;
@@ -40,6 +41,7 @@ import ghidra.program.model.data.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.Function.FunctionUpdateType;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.SymbolUtilities;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
import ghidra.util.exception.DuplicateNameException;
@@ -52,6 +54,8 @@ import ghidra.util.task.TaskMonitor;
*/
public class CliTableMethodDef extends CliAbstractTable {
private static final int CLITABLEMETHODDEF_PINVOKE_JUMP_LENGTH = 0x06;
public class CliMethodDefRow extends CliAbstractTableRow {
public int RVA;
public short ImplFlags; // MethodImplAttributes
@@ -63,6 +67,42 @@ public class CliTableMethodDef extends CliAbstractTable {
private static final int NEXT_ROW_PARAM_INIT_VALUE = -1;
private int nextRowParamIndex = NEXT_ROW_PARAM_INIT_VALUE;
private static final int METHODIMPLATTRIBUTES_CODETYPE_IL = 0x00;
private static final int METHODIMPLATTRIBUTES_CODETYPE_NATIVE = 0x01;
private static final int METHODIMPLATTRIBUTES_CODETYPE_OPTIL = 0x02;
private static final int METHODIMPLATTRIBUTES_CODETYPE_RUNTIME = 0x03;
private static final int METHODIMPLATTRIBUTES_MANAGED_MANAGED = 0x00;
private static final int METHODIMPLATTRIBUTES_MANAGED_UNMANAGED = 0x04;
private static final int METHODIMPLATTRIBUTES_FORWARDREF = 0x10;
private static final int METHODIMPLATTRIBUTES_PRESERVESIG = 0x80;
private static final int METHODIMPLATTRIBUTES_INTERNALCALL = 0x1000;
private static final int METHODIMPLATTRIBUTES_SYNCHRONIZED = 0x20;
private static final int METHODIMPLATTRIBUTES_NOINLINING = 0x08;
private static final int METHODIMPLATTRIBUTES_AGGRESSIVEINLINING = 0x1000;
private static final int METHODIMPLATTRIBUTES_MAXMETHODIMPLVAL = 0xffff;
private static final int METHODATTRIBUTES_MEMBERACCESS_COMPILERCONTROLLED = 0x00;
private static final int METHODATTRIBUTES_MEMBERACCESS_PRIVATE = 0x01;
private static final int METHODATTRIBUTES_MEMBERACCESS_FAMANDASSEM = 0x02;
private static final int METHODATTRIBUTES_MEMBERACCESS_ASSEM = 0x03;
private static final int METHODATTRIBUTES_MEMBERACCESS_FAMILY = 0x04;
private static final int METHODATTRIBUTES_MEMBERACCESS_FAMORASSEM = 0x05;
private static final int METHODATTRIBUTES_MEMBERACCESS_PUBLIC = 0x06;
private static final int METHODATTRIBUTES_STATIC = 0x10;
private static final int METHODATTRIBUTES_FINAL = 0x20;
private static final int METHODATTRIBUTES_VIRTUAL = 0x40;
private static final int METHODATTRIBUTES_HIDEBYSIG = 0x80;
private static final int METHODATTRIBUTES_VTABLELAYOUT_REUSESLOT = 0x0000;
private static final int METHODATTRIBUTES_VTABLELAYOUT_NEWSLOT = 0x0100;
private static final int METHODATTRIBUTES_STRICT = 0x0200;
private static final int METHODATTRIBUTES_ABSTRACT = 0x0400;
private static final int METHODATTRIBUTES_SPECIALNAME = 0x0800;
private static final int METHODATTRIBUTES_PINVOKEIMPL = 0x2000;
private static final int METHODATTRIBUTES_UNMANAGEDEXPORT = 0x08;
private static final int METHODATTRIBUTES_RTSPECIALNAME = 0x1000;
private static final int METHODATTRIBUTES_HASSECURITY = 0x4000;
private static final int METHODATTRIBUTES_REQUIRESECOBJECT = 0x8000;
public CliMethodDefRow(int rva, short implFlags, short flags, int nameIndex, int sigIndex,
int paramIndex) {
this.RVA = rva;
@@ -141,6 +181,28 @@ public class CliTableMethodDef extends CliAbstractTable {
CliEnumMethodImplAttributes.dataType.getName(ImplFlags & 0xffff),
CliEnumMethodAttributes.dataType.getName(Flags & 0xffff));
}
// Static functions have four parameters but the first is an implied
// pointer to the object they're associated with. It's not in the
// ParameterTable and looking for the extra parameter will walk
// you into the parameter of another function.
boolean isStatic() {
return (Flags & METHODATTRIBUTES_STATIC) == METHODATTRIBUTES_STATIC;
}
boolean isPInvokeImpl() {
return (Flags & METHODATTRIBUTES_PINVOKEIMPL) == METHODATTRIBUTES_PINVOKEIMPL;
}
boolean isNative() {
return (ImplFlags &
METHODIMPLATTRIBUTES_CODETYPE_NATIVE) == METHODIMPLATTRIBUTES_CODETYPE_NATIVE;
}
boolean isManaged() {
return (ImplFlags &
METHODIMPLATTRIBUTES_CODETYPE_IL) == METHODIMPLATTRIBUTES_CODETYPE_IL;
}
}
public CliTableMethodDef(BinaryReader reader, CliStreamMetadata stream, CliTypeTable tableId)
@@ -159,7 +221,7 @@ public class CliTableMethodDef extends CliAbstractTable {
}
lastRow = row;
}
reader.setPointerIndex(this.readerOffset); // TODO: why do this, also elsewhere
reader.setPointerIndex(this.readerOffset);
}
@Override
@@ -167,54 +229,64 @@ public class CliTableMethodDef extends CliAbstractTable {
NTHeader ntHeader)
throws DuplicateNameException, CodeUnitInsertionException, IOException {
int rvaZero = 0;
int methodRowIndex = 0;
for (CliAbstractTableRow method : rows) {
methodRowIndex++;
CliMethodDefRow methodRow = (CliMethodDefRow) method;
// This indicates the method is abstract, runtime, or PInvokeImpl
if (methodRow.RVA == 0) {
rvaZero++;
continue;
}
Address addr = PeUtils.getMarkupAddress(program, isBinary, ntHeader, methodRow.RVA);
Address startAddr = addr;
Address endAddr = addr;
// Create MethodDef at this RVA
BinaryReader reader =
new BinaryReader(new MemoryByteProvider(program.getMemory(), addr),
!program.getMemory().isBigEndian());
CliMethodDef methodDef = new CliMethodDef(addr, reader);
PeUtils.createData(program, addr, methodDef.toDataType(), log);
// Get the function's address space, default to zero-length just in case
Address startAddr = addr.add(methodDef.toDataType().getLength());
Address endAddr = startAddr;
if (methodDef.getMethodSize() > 0) {
endAddr = startAddr.add(methodDef.getMethodSize() - 1);
if (methodRow.isPInvokeImpl() && methodRow.isNative()) {
endAddr = startAddr.add(CLITABLEMETHODDEF_PINVOKE_JUMP_LENGTH - 1);
}
else {
// Create MethodDef at this RVA
BinaryReader reader =
new BinaryReader(new MemoryByteProvider(program.getMemory(), addr),
!program.getMemory().isBigEndian());
CliMethodDef methodDef = new CliMethodDef(addr, reader);
DataType methodDefDataType = methodDef.toDataType();
PeUtils.createData(program, addr, methodDefDataType, log);
// Get the function's address space, default to zero-length just in case
startAddr = addr.add(methodDefDataType.getLength());
endAddr = startAddr;
if (methodDef.getMethodSize() > 0) {
endAddr = startAddr.add(methodDef.getMethodSize() - 1);
}
// Do extra data sections in MethodDef
if (methodDef.hasMoreSections()) {
int extraSectionOffset =
methodDefDataType.getLength() + methodDef.getMethodSize();
// Round up to the next offset divisible by 4
extraSectionOffset = ((extraSectionOffset + 3) / 4) * 4;
reader.setPointerIndex(extraSectionOffset);
CliMethodExtraSections extraSections = new CliMethodExtraSections(reader);
Address extraSectionAddr = addr.add(extraSectionOffset);
PeUtils.createData(program, extraSectionAddr, extraSections.toDataType(), log);
}
}
AddressSetView funcAddrSet = new AddressSet(startAddr, endAddr);
// Let Ghidra assign a default function name and then try to decode the
// real one if it exists
String funcName = null;
if (methodRow.nameIndex > 0) {
funcName = metadataStream.getStringsStream().getString(methodRow.nameIndex);
}
// Do extra data sections in MethodDef
if (methodDef.hasMoreSections()) {
int extraSectionOffset =
methodDef.toDataType().getLength() + methodDef.getMethodSize();
// Round up to the next offset divisible by 4
extraSectionOffset = ((extraSectionOffset + 3) / 4) * 4;
reader.setPointerIndex(extraSectionOffset);
CliMethodExtraSections extraSections = new CliMethodExtraSections(reader);
Address extraSectionAddr = addr.add(extraSectionOffset);
PeUtils.createData(program, extraSectionAddr, extraSections.toDataType(), log);
funcName = SymbolUtilities.replaceInvalidChars(
metadataStream.getStringsStream().getString(methodRow.nameIndex), true);
}
// Get the function signature blob
@@ -227,27 +299,136 @@ public class CliTableMethodDef extends CliAbstractTable {
metadataStream.getBlobStream().updateBlob(methodSig, sigAddr, program);
DataType returnType = methodSig.getReturnType().getExecutionDataType();
// Pull apart the function parameter names and types
int maxSequence = 0;
int stackOffset = 0;
CliParam paramTypes[] = methodSig.getParamTypes();
int paramCount = paramTypes.length;
CliTableParam paramTable = (CliTableParam) metadataStream.getTable(CliTypeTable.Param);
ParameterImpl parameters[] = new ParameterImpl[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
// Store the parameters in a Hashtable because by the time processing
// finishes the number of actual parameters might change
HashMap<Integer, ParameterImpl> parameterList = new HashMap<Integer, ParameterImpl>();
// Some Static function first parameters being pointers to a ValueType
// have the same number of parameters specified, but one or more are implied
// pointers to the object they're associated with. It's not in the Parameter
// Table and looking for the extra parameter in the table will walk you
// into the parameter list of another function.
ParameterImpl staticParameter = null;
if (methodRow.isStatic() && paramCount > 0) {
CliParam staticParam = paramTypes[0];
String paramName = "";
// Walk the path from the ELEMENT_TYPE_PTR to the ELEMENT_TYPE_VALUETYPE
if (staticParam.getType() instanceof CliTypePtr) {
CliTypePtr ptrToValueType = (CliTypePtr) staticParam.getType();
if (ptrToValueType.getType() instanceof CliTypeValueType) {
CliTypeValueType valueType = (CliTypeValueType) ptrToValueType.getType();
// Get the table and row specifying the type name
CliTypeTable tableType = valueType.getTable();
int rowIndex = valueType.getRowIndex();
int paramNameStringIndex = 0;
CliAbstractTable table = metadataStream.getTable(tableType);
CliAbstractTableRow row = table.getRow(rowIndex);
if (tableType.id() == tableType.TypeDef.id()) {
CliTypeDefRow typeDefRow = (CliTypeDefRow) row;
paramNameStringIndex = typeDefRow.typeNameIndex;
}
else if (tableType.id() == tableType.TypeRef.id()) {
CliTypeRefRow typeRefRow = (CliTypeRefRow) row;
paramNameStringIndex = typeRefRow.typeNameIndex;
}
if (paramNameStringIndex > 0) {
paramName =
metadataStream.getStringsStream().getString(paramNameStringIndex);
paramName = SymbolUtilities.replaceInvalidChars(paramName, true);
DataType dataType = staticParam.getExecutionDataType();
try {
staticParameter =
new ParameterImpl(paramName, dataType, stackOffset, program);
}
catch (InvalidInputException e) {
Msg.warn(this, "Error processing parameter \"" + paramName +
"\" in function \"" + funcName + "\": " + e.getMessage());
}
stackOffset += dataType.getLength();
paramCount--;
}
}
}
}
// Pull apart the function's Param table entries
for (int i = 0; i < paramCount; i++) {
CliParamRow paramRow = (CliParamRow) paramTable.getRow(methodRow.paramIndex + i);
String paramName = metadataStream.getStringsStream().getString(paramRow.nameIndex);
if (paramRow.sequence > maxSequence) {
maxSequence = paramRow.sequence;
}
String paramName = SymbolUtilities.replaceInvalidChars(
metadataStream.getStringsStream().getString(paramRow.nameIndex), true);
DataType dataType = paramTypes[i].getExecutionDataType();
try {
parameters[i] = new ParameterImpl(paramName, dataType, stackOffset, program);
}
catch (InvalidInputException e) {
Msg.warn(this, "Error processing parameter \"" + paramName +
"\" in function \"" + funcName + "\": " + e.getMessage());
if (paramRow.sequence == 0) {
// Parameters with a 0 sequence number are the return type,
// reduce the size of the array and put any previously discovered
// parameters into it
returnType = dataType;
}
else {
// Parameters are placed in the proper order based on the sequence
// field (1-based) to compensate for some static methods having an implied
// first parameter that won't be represented in the Parameter Table
// and some return types that are represented as parameters.
try {
parameterList.put((int) paramRow.sequence,
new ParameterImpl(paramName, dataType, stackOffset, program));
}
catch (InvalidInputException e) {
Msg.warn(this, "Error processing parameter \"" + paramName +
"\" in function \"" + funcName + "\": " + e.getMessage());
}
stackOffset += dataType.getLength();
stackOffset += dataType.getLength();
}
}
ParameterImpl[] parameters = new ParameterImpl[maxSequence];
parameterList.forEach((key, value) ->
// Sequences are 1-based
parameters[key - 1] = value);
// For static functions, fill in the pointer to ValueType
// parameters that are implied before the actual parameters
if (methodRow.isStatic()) {
if (staticParameter != null) {
for (int i = 0; i < parameters.length; i++) {
if (parameters[i] == null) {
ParameterImpl param = null;
try {
param = new ParameterImpl(staticParameter.getName() + i,
staticParameter.getDataType(), staticParameter.getStackOffset(),
staticParameter.getProgram());
}
catch (InvalidInputException e1) {
Msg.warn(this,
"Couldn't clone " + staticParameter.getName() +
" implied static function parameter in function : " +
funcName + "in position " + i);
}
parameters[i] = param;
}
}
}
}
try {
@@ -257,15 +438,44 @@ public class CliTableMethodDef extends CliAbstractTable {
newFunc.updateFunction(null, null, FunctionUpdateType.DYNAMIC_STORAGE_ALL_PARAMS,
true, SourceType.ANALYSIS, parameters);
}
catch (NullPointerException e) {
Msg.warn(this, "Error processing function \"" + funcName + "\" (" + methodRowIndex +
"): Bad parameters provided");
}
catch (InvalidInputException e) {
Msg.warn(this, "Error processing function \"" + funcName + "\"");
Msg.warn(this, "Error processing function \" (\" + methodRowIndex + \")" +
funcName + "\": Invalid function");
}
catch (OverlappingFunctionException e) {
Msg.warn(this, "Error processing function \"" + funcName + "\"");
String err = "Error processing function \" (\" + methodRowIndex + \")" + funcName +
"\": Overlapping function (" + startAddr + ", " + endAddr + ": ";
Function existingFuncA = program.getFunctionManager().getFunctionAt(startAddr);
Function existingFuncB = program.getFunctionManager().getFunctionAt(endAddr);
if (existingFuncA != null && existingFuncB == null) {
err = err + existingFuncA.getName();
}
else if (existingFuncA == null && existingFuncB != null) {
err = err + existingFuncB.getName();
}
else if (existingFuncA != null && existingFuncA == existingFuncB) {
err = err + existingFuncA.getName();
}
err = err + ")";
Msg.warn(this, err);
}
catch (DuplicateNameException e) {
String paramNames = "";
for (int i = 0; i < parameters.length - 1; i++) {
paramNames += parameters[i].getName() + ", ";
}
paramNames += parameters[parameters.length - 1].getName();
Msg.warn(this, "Error processing function \"" + funcName + "\" (" + methodRowIndex +
"): Duplicate parameter name (" + paramNames + ")");
}
}
if (rvaZero > 0) {
Msg.warn(this, rvaZero + " methods with RVA 0");
}
}

View File

@@ -31,7 +31,14 @@ public class CliTableParam extends CliAbstractTable {
public short flags;
public short sequence;
public int nameIndex;
private static final int PARAMATTRIBUTES_IN = 0x1;
private static final int PARAMATTRIBUTES_OUT = 0x2;
private static final int PARAMATTRIBUTES_OPTIONAL = 0x10;
private static final int PARAMATTRIBUTES_HASDEFAULT = 0x1000;
private static final int PARAMATTRIBUTES_HASFIELDMARSHAL = 0x2000;
private static final int PARAMATTRIBUTES_UNUSED = 0xCFE0;
public CliParamRow(short flags, short sequence, int nameIndex) {
super();
this.flags = flags;
@@ -46,11 +53,13 @@ public class CliTableParam extends CliAbstractTable {
CliEnumParamAttributes.dataType.getName(flags & 0xffff), sequence);
}
}
public CliTableParam(BinaryReader reader, CliStreamMetadata stream, CliTypeTable tableId) throws IOException {
public CliTableParam(BinaryReader reader, CliStreamMetadata stream, CliTypeTable tableId)
throws IOException {
super(reader, stream, tableId);
for (int i = 0; i < this.numRows; i++) {
CliParamRow row = new CliParamRow(reader.readNextShort(), reader.readNextShort(), readStringIndex(reader));
CliParamRow row = new CliParamRow(reader.readNextShort(), reader.readNextShort(),
readStringIndex(reader));
rows.add(row);
strings.add(row.nameIndex);
}
@@ -59,9 +68,9 @@ public class CliTableParam extends CliAbstractTable {
@Override
public StructureDataType getRowDataType() {
StructureDataType rowDt = new StructureDataType(new CategoryPath(PATH), "ParamRow",0);
StructureDataType rowDt = new StructureDataType(new CategoryPath(PATH), "ParamRow", 0);
rowDt.add(CliEnumParamAttributes.dataType, "Flags", "bitmask of type ParamAttributes");
rowDt.add( WORD, "Sequence", "constant");
rowDt.add(WORD, "Sequence", "constant");
rowDt.add(metadataStream.getStringIndexDataType(), "Name", "index into String heap");
return rowDt;
}

View File

@@ -4,9 +4,9 @@
* 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.
@@ -90,6 +90,7 @@ public class CliTableStandAloneSig extends CliAbstractTable {
throws DuplicateNameException, CodeUnitInsertionException, IOException {
for (CliAbstractTableRow row : rows) {
Integer sigIndex = ((CliStandAloneSigRow) row).signatureIndex;
CliBlob blob =
metadataStream.getBlobStream().getBlob(((CliStandAloneSigRow) row).signatureIndex);
Address sigAddr = CliAbstractStream.getStreamMarkupAddress(program, isBinary, monitor,