GP-3832 importer/exporter for SARIF

This commit is contained in:
d-millar 2023-11-30 16:17:06 -05:00 committed by ghidra1
parent c225fac124
commit 31ca84453a
174 changed files with 15711 additions and 334 deletions

View file

@ -0,0 +1,71 @@
/* ###
* 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.plugin.core.datamgr.actions;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import com.google.gson.JsonObject;
import docking.widgets.tree.GTree;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.ISF.IsfDataTypeWriter;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.Task;
import ghidra.util.task.TaskMonitor;
public class DataTypeWriterTask extends Task {
private final DataTypeManager programDataTypeMgr;
private final List<DataType> dataTypeList;
private final File file;
private final GTree gTree;
public DataTypeWriterTask(GTree gTree, DataTypeManager programDataTypeMgr, List<DataType> dataTypeList, File file) {
super("Export Data Types", true, false, true);
this.gTree = gTree;
this.programDataTypeMgr = programDataTypeMgr;
this.dataTypeList = dataTypeList;
this.file = file;
}
@Override
public void run(TaskMonitor monitor) {
try {
//monitor.setMessage("Export to " + file.getName() + "...");
FileWriter baseWriter = file == null ? null : new FileWriter(file);
IsfDataTypeWriter dataTypeWriter = new IsfDataTypeWriter(programDataTypeMgr, dataTypeList, baseWriter);
try {
JsonObject object = dataTypeWriter.getRootObject(monitor);
if (file != null) {
dataTypeWriter.write(object);
}
} finally {
dataTypeWriter.close();
}
} catch (CancelledException e) {
// user cancelled; ignore
} catch (IOException e) {
Msg.showError(getClass(), gTree, "Export Data Types Failed", "Error exporting Data Types: " + e);
return;
}
}
}

View file

@ -188,14 +188,14 @@ public class ExportToIsfAction extends DockingAction {
fileChooser.dispose(); fileChooser.dispose();
} }
private class DataTypeWriterTask extends Task { public class DataTypeWriterTask extends Task {
private final DataTypeManager programDataTypeMgr; private final DataTypeManager programDataTypeMgr;
private final List<DataType> dataTypeList; private final List<DataType> dataTypeList;
private final File file; private final File file;
private final GTree gTree; private final GTree gTree;
DataTypeWriterTask(GTree gTree, DataTypeManager programDataTypeMgr, public DataTypeWriterTask(GTree gTree, DataTypeManager programDataTypeMgr,
List<DataType> dataTypeList, File file) { List<DataType> dataTypeList, File file) {
super("Export Data Types", true, false, true); super("Export Data Types", true, false, true);
this.gTree = gTree; this.gTree = gTree;
@ -209,12 +209,9 @@ public class ExportToIsfAction extends DockingAction {
try { try {
monitor.setMessage("Export to " + file.getName() + "..."); monitor.setMessage("Export to " + file.getName() + "...");
IsfDataTypeWriter dataTypeWriter = IsfDataTypeWriter dataTypeWriter =
new IsfDataTypeWriter(programDataTypeMgr, new FileWriter(file)); new IsfDataTypeWriter(programDataTypeMgr, dataTypeList, new FileWriter(file));
try { try {
for (DataType dataType : dataTypeList) {
dataTypeWriter.requestType(dataType);
}
JsonObject object = dataTypeWriter.getRootObject(monitor); JsonObject object = dataTypeWriter.getRootObject(monitor);
dataTypeWriter.write(object); dataTypeWriter.write(object);
} }

View file

@ -130,7 +130,7 @@ public class IsfClientHandler {
private String lookType(String ns, String key) throws IOException { private String lookType(String ns, String key) throws IOException {
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns)); IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
isfWriter.setSkipSymbols(true); isfWriter.setSkipSymbols(true);
isfWriter.requestType(key); //isfWriter.requestType(key);
return writeFrom(isfWriter); return writeFrom(isfWriter);
} }
@ -198,7 +198,7 @@ public class IsfClientHandler {
private IsfDataTypeWriter createDataTypeWriter(DataTypeManager dtm) throws IOException { private IsfDataTypeWriter createDataTypeWriter(DataTypeManager dtm) throws IOException {
StringWriter out = new StringWriter(); StringWriter out = new StringWriter();
return new IsfDataTypeWriter(dtm, out); return new IsfDataTypeWriter(dtm, null, out);
} }
private String writeFrom(IsfDataTypeWriter dataTypeWriter) throws IOException { private String writeFrom(IsfDataTypeWriter dataTypeWriter) throws IOException {

View file

@ -0,0 +1,60 @@
/* ###
* 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.program.model.data.ISF;
import java.util.ArrayList;
import java.util.List;
import ghidra.docking.settings.Settings;
import ghidra.docking.settings.SettingsDefinition;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ISF.AbstractIsfWriter.Exclude;
public abstract class AbstractIsfObject implements IsfObject {
@Exclude
public String name;
@Exclude
public String location;
@Exclude
public List<IsfSetting> settings;
public AbstractIsfObject(DataType dt) {
if (dt != null) {
name = dt.getName();
location = dt.getCategoryPath().getPath();
Settings defaultSettings = dt.getDefaultSettings();
processSettings(dt, defaultSettings);
}
}
protected void processSettings(DataType dt, Settings defaultSettings) {
SettingsDefinition[] settingsDefinitions = dt.getSettingsDefinitions();
for (SettingsDefinition def : settingsDefinitions) {
if (def.hasValue(defaultSettings)) {
settings = new ArrayList<>();
String[] names = defaultSettings.getNames();
for (String n : names) {
Object value = defaultSettings.getValue(n);
if (value != null) {
IsfSetting setting = new IsfSetting(n, value);
settings.add(setting);
}
}
}
}
}
}

View file

@ -0,0 +1,108 @@
/* ###
* 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.program.model.data.ISF;
import java.io.Closeable;
import java.io.IOException;
import java.io.Writer;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonWriter;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public abstract class AbstractIsfWriter implements Closeable {
protected JsonWriter writer;
protected Gson gson = new GsonBuilder().setPrettyPrinting().create();
protected JsonObject root = new JsonObject();
protected JsonArray objects = new JsonArray();
public AbstractIsfWriter(Writer baseWriter) throws IOException {
if (writer != null) {
this.writer = new JsonWriter(baseWriter);
writer.setIndent(" ");
}
this.gson = new GsonBuilder().addSerializationExclusionStrategy(strategy).setPrettyPrinting().create();
}
protected abstract void genRoot(TaskMonitor monitor) throws CancelledException, IOException;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Exclude {
// EMPTY
}
// Am setting this as the default, but it's possible we may want more latitude
// in the future
protected boolean STRICT = true;
// @Exclude used for properties that might be desirable for a non-STRICT
// implementation.
ExclusionStrategy strategy = new ExclusionStrategy() {
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
@Override
public boolean shouldSkipField(FieldAttributes field) {
return STRICT && field.getAnnotation(Exclude.class) != null;
}
};
public JsonObject getRootObject(TaskMonitor monitor) throws CancelledException, IOException {
genRoot(monitor);
return root;
}
public JsonArray getResults() {
return objects;
}
public JsonElement getTree(Object obj) {
return gson.toJsonTree(obj);
}
public Object getObject(JsonElement element, Class<? extends Object> clazz) {
return gson.fromJson(element, clazz);
}
public void write(JsonObject object) {
gson.toJson(object, writer);
}
public void close() throws IOException {
if (writer != null) {
writer.flush();
writer.close();
}
}
}

View file

@ -17,16 +17,15 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.BuiltInDataType; import ghidra.program.model.data.BuiltInDataType;
public class IsfBuiltIn implements IsfObject { public class IsfBuiltIn extends AbstractIsfObject {
public Integer size; public Integer size;
public Boolean signed;
public String kind; public String kind;
public String endian; public String endian;
public IsfBuiltIn(BuiltInDataType builtin) { public IsfBuiltIn(BuiltInDataType builtin) {
super(builtin);
size = IsfUtilities.getLength(builtin); size = IsfUtilities.getLength(builtin);
signed = IsfUtilities.getSigned(builtin);
kind = IsfUtilities.getBuiltInKind(builtin); kind = IsfUtilities.getBuiltInKind(builtin);
endian = IsfUtilities.getEndianness(builtin); endian = IsfUtilities.getEndianness(builtin);
} }

View file

@ -16,9 +16,9 @@
package ghidra.program.model.data.ISF; package ghidra.program.model.data.ISF;
import ghidra.program.model.data.DataTypeComponent; import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude; import ghidra.program.model.data.ISF.AbstractIsfWriter.Exclude;
public class IsfComponent implements IsfObject { public class IsfComponent extends AbstractIsfObject {
public Integer offset; public Integer offset;
public IsfObject type; public IsfObject type;
@ -30,16 +30,25 @@ public class IsfComponent implements IsfObject {
@Exclude @Exclude
public String field_name; public String field_name;
@Exclude @Exclude
public Boolean noFieldName;
@Exclude
public String comment; public String comment;
public IsfComponent(DataTypeComponent component, IsfObject typeObj) { public IsfComponent(DataTypeComponent component, IsfObject typeObj) {
super(component.getDataType());
offset = component.getOffset(); offset = component.getOffset();
type = typeObj; type = typeObj;
field_name = component.getFieldName(); field_name = component.getFieldName();
if (field_name == null || field_name.equals("")) {
noFieldName = true;
}
ordinal = component.getOrdinal(); ordinal = component.getOrdinal();
length = component.getLength(); length = component.getLength();
comment = component.getComment(); comment = component.getComment();
processSettings(component.getDataType(), component.getDefaultSettings());
} }
} }

View file

@ -15,52 +15,50 @@
*/ */
package ghidra.program.model.data.ISF; package ghidra.program.model.data.ISF;
import java.util.*;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import ghidra.program.model.data.*; import ghidra.program.model.data.Composite;
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude; import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.Structure;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class IsfComposite implements IsfObject { public class IsfComposite extends AbstractIsfObject {
public String kind; public String kind;
public Integer size; public Integer size;
public JsonObject fields; public JsonObject fields;
@Exclude
public int alignment;
public IsfComposite(Composite composite, IsfDataTypeWriter writer, TaskMonitor monitor) { public IsfComposite(Composite composite, IsfDataTypeWriter writer, TaskMonitor monitor) {
super(composite);
size = composite.getLength(); size = composite.getLength();
kind = composite instanceof Structure ? "struct" : "union"; kind = composite instanceof Structure ? "struct" : "union";
alignment = composite.getAlignment();
DataTypeComponent[] components = composite.getComponents(); DataTypeComponent[] components = composite.getComponents();
Map<String, DataTypeComponent> comps = new HashMap<>(); if (components.length == 0) {
for (DataTypeComponent component : components) { // NB: composite.getLength always returns > 0
String key = component.getFieldName(); size = 0;
if (key == null) {
key = component.getDefaultFieldName();
}
comps.put(key, component);
} }
ArrayList<String> keylist = new ArrayList<>(comps.keySet());
Collections.sort(keylist);
fields = new JsonObject(); fields = new JsonObject();
for (String key : keylist) { for (DataTypeComponent component : components) {
if (monitor.isCancelled()) { if (monitor.isCancelled()) {
break; break;
} }
DataTypeComponent component = comps.get(key);
IsfObject type = writer.getObjectTypeDeclaration(component); IsfObject type = writer.getObjectTypeDeclaration(component);
IsfComponent cobj = new IsfComponent(component, type); IsfComponent cobj = getComponent(component, type);
String key = component.getFieldName();
if (key == null) {
key = DataTypeComponent.DEFAULT_FIELD_NAME_PREFIX + component.getOrdinal();
if (component.getParent() instanceof Structure) {
key += "_0x" + Integer.toHexString(component.getOffset());
}
}
fields.add(key, writer.getTree(cobj)); fields.add(key, writer.getTree(cobj));
} }
}
protected IsfComponent getComponent(DataTypeComponent component, IsfObject type) {
return new IsfComponent(component, type);
} }
} }

View file

@ -17,13 +17,14 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.Array; import ghidra.program.model.data.Array;
public class IsfDataTypeArray implements IsfObject { public class IsfDataTypeArray extends AbstractIsfObject {
public String kind; public String kind;
public Integer count; public Integer count;
public IsfObject subtype; public IsfObject subtype;
public IsfDataTypeArray(Array arr, IsfObject typeObj) { public IsfDataTypeArray(Array arr, IsfObject typeObj) {
super(arr);
kind = IsfUtilities.getKind(arr); kind = IsfUtilities.getKind(arr);
count = arr.getNumElements(); count = arr.getNumElements();
subtype = typeObj; subtype = typeObj;

View file

@ -16,9 +16,9 @@
package ghidra.program.model.data.ISF; package ghidra.program.model.data.ISF;
import ghidra.program.model.data.BitFieldDataType; import ghidra.program.model.data.BitFieldDataType;
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude; import ghidra.program.model.data.ISF.AbstractIsfWriter.Exclude;
public class IsfDataTypeBitField implements IsfObject { public class IsfDataTypeBitField extends AbstractIsfObject {
public String kind; public String kind;
public Integer bit_length; public Integer bit_length;
@ -31,6 +31,7 @@ public class IsfDataTypeBitField implements IsfObject {
private int storage_size; private int storage_size;
public IsfDataTypeBitField(BitFieldDataType bf, int componentOffset, IsfObject typeObj) { public IsfDataTypeBitField(BitFieldDataType bf, int componentOffset, IsfObject typeObj) {
super(bf);
kind = IsfUtilities.getKind(bf); kind = IsfUtilities.getKind(bf);
bit_length = bf.getBitSize(); bit_length = bf.getBitSize();
bit_offset = bf.getBitOffset(); bit_offset = bf.getBitOffset();

View file

@ -17,14 +17,15 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
public class IsfDataTypeDefault implements IsfObject { public class IsfDataTypeDefault extends AbstractIsfObject {
public String kind; public String kind;
public String name; int size;
public IsfDataTypeDefault(DataType dt) { public IsfDataTypeDefault(DataType dt) {
super(dt);
kind = IsfUtilities.getKind(dt); kind = IsfUtilities.getKind(dt);
name = dt.getName(); size = dt.getLength();
} }
} }

View file

@ -17,12 +17,13 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
public class IsfDataTypeTypeDef implements IsfObject { public class IsfDataTypeTypeDef extends AbstractIsfObject {
public String kind; public String kind;
public IsfObject subtype; public IsfObject subtype;
public IsfDataTypeTypeDef(DataType dt, IsfObject typeObj) { public IsfDataTypeTypeDef(DataType dt, IsfObject typeObj) {
super(dt);
kind = IsfUtilities.getKind(dt); kind = IsfUtilities.getKind(dt);
subtype = typeObj; subtype = typeObj;
} }

View file

@ -17,20 +17,43 @@ package ghidra.program.model.data.ISF;
import java.io.IOException; import java.io.IOException;
import java.io.Writer; import java.io.Writer;
import java.lang.annotation.*; import java.util.ArrayList;
import java.util.*; import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import com.google.gson.*; import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.stream.JsonWriter; import com.google.gson.stream.JsonWriter;
import ghidra.program.database.data.ProgramDataTypeManager; import ghidra.program.database.data.ProgramDataTypeManager;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFormatException; import ghidra.program.model.address.AddressFormatException;
import ghidra.program.model.data.*; import ghidra.program.model.data.Array;
import ghidra.program.model.data.BitFieldDataType;
import ghidra.program.model.data.BuiltInDataType;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.DataOrganization;
import ghidra.program.model.data.DataOrganizationImpl;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.Dynamic;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
import ghidra.program.model.data.FactoryDataType;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.model.symbol.ReferenceManager;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.Msg; import ghidra.util.Msg;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -40,29 +63,28 @@ import ghidra.util.task.TaskMonitor;
* *
* The ISF JSON should be valid for Volatility is STRICT==true. * The ISF JSON should be valid for Volatility is STRICT==true.
*/ */
public class IsfDataTypeWriter { public class IsfDataTypeWriter extends AbstractIsfWriter {
private Map<DataType, IsfObject> resolved = new HashMap<>(); protected Map<DataType, IsfObject> resolved = new HashMap<>();
private Map<String, DataType> resolvedTypeMap = new HashMap<>(); private Map<String, DataType> resolvedTypeMap = new HashMap<>();
private List<String> deferredKeys = new ArrayList<>(); public List<String> deferredKeys = new ArrayList<>();
private Writer baseWriter; private Writer baseWriter;
private JsonWriter writer;
private Gson gson = new GsonBuilder().setPrettyPrinting().create();
private DataTypeManager dtm; protected DataTypeManager dtm;
private DataOrganization dataOrganization; private DataOrganization dataOrganization;
private JsonObject data = new JsonObject(); protected JsonObject data = new JsonObject();
private JsonObject metadata = new JsonObject(); protected JsonElement metadata;
private JsonObject baseTypes = new JsonObject(); protected JsonElement baseTypes;
private JsonObject userTypes = new JsonObject(); protected JsonElement userTypes;
private JsonObject enums = new JsonObject(); protected JsonElement enums;
private JsonObject symbols = new JsonObject(); protected JsonElement functions;
protected JsonElement symbols;
private List<Address> requestedAddresses = new ArrayList<>(); private List<Address> requestedAddresses = new ArrayList<>();
private List<String> requestedSymbols = new ArrayList<>(); private List<String> requestedSymbols = new ArrayList<>();
private List<String> requestedTypes = new ArrayList<>(); // private List<String> requestedTypes = new ArrayList<>();
private List<DataType> requestedDataTypes = new ArrayList<>(); private List<DataType> requestedDataTypes = new ArrayList<>();
private boolean skipSymbols = false; private boolean skipSymbols = false;
private boolean skipTypes = false; private boolean skipTypes = false;
@ -70,11 +92,13 @@ public class IsfDataTypeWriter {
/** /**
* Constructs a new instance of this class using the given writer * Constructs a new instance of this class using the given writer
* *
* @param dtm data-type manager corresponding to target program or null for default * @param dtm data-type manager corresponding to target program or null
* for default
* @param baseWriter the writer to use when writing data types * @param baseWriter the writer to use when writing data types
* @throws IOException if there is an exception writing the output * @throws IOException if there is an exception writing the output
*/ */
public IsfDataTypeWriter(DataTypeManager dtm, Writer baseWriter) throws IOException { public IsfDataTypeWriter(DataTypeManager dtm, List<DataType> target, Writer baseWriter) throws IOException {
super(baseWriter);
this.dtm = dtm; this.dtm = dtm;
if (dtm != null) { if (dtm != null) {
dataOrganization = dtm.getDataOrganization(); dataOrganization = dtm.getDataOrganization();
@ -82,66 +106,43 @@ public class IsfDataTypeWriter {
if (dataOrganization == null) { if (dataOrganization == null) {
dataOrganization = DataOrganizationImpl.getDefaultOrganization(); dataOrganization = DataOrganizationImpl.getDefaultOrganization();
} }
this.baseWriter = baseWriter;
this.writer = new JsonWriter(baseWriter); metadata = new JsonObject();
writer.setIndent(" "); baseTypes = new JsonObject();
this.gson = new GsonBuilder() userTypes = new JsonObject();
.addSerializationExclusionStrategy(strategy) enums = new JsonObject();
.setPrettyPrinting() functions = new JsonObject();
.create(); symbols = new JsonObject();
requestedDataTypes = target;
STRICT = true;
} }
@Retention(RetentionPolicy.RUNTIME) @Override
@Target(ElementType.FIELD) protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
public @interface Exclude {
//EMPTY
}
// Am setting this as the default, but it's possible we may want more latitude in the future
private boolean STRICT = true;
// @Exclude used for properties that might be desirable for a non-STRICT implementation.
ExclusionStrategy strategy = new ExclusionStrategy() {
@Override
public boolean shouldSkipClass(Class<?> clazz) {
return false;
}
@Override
public boolean shouldSkipField(FieldAttributes field) {
return STRICT && field.getAnnotation(Exclude.class) != null;
}
};
/**
* Exports all data types in the list as ISF JSON.
*
* @param monitor the task monitor
* @return the resultant JSON object
* @throws IOException if there is an exception writing the output
* @throws CancelledException if the action is cancelled by the user
*/
public JsonObject getRootObject(TaskMonitor monitor)
throws IOException, CancelledException {
genMetadata(); genMetadata();
genTypes(monitor); genTypes(monitor);
genSymbols(); genSymbols(monitor);
genRoot();
return data;
}
private void genRoot() {
data.add("metadata", metadata); data.add("metadata", metadata);
data.add("base_types", baseTypes); data.add("base_types", baseTypes);
data.add("user_types", userTypes); data.add("user_types", userTypes);
data.add("enums", enums); data.add("enums", enums);
// Would be nice to support this in the futere, but Volatility does not // Would be nice to support this in the future, but Volatility does not
//data.add("typedefs", typedefs); // data.add("functions", functions);
data.add("symbols", symbols); data.add("symbols", symbols);
} }
public void add(JsonElement parent, String optKey, JsonElement child) {
if (parent instanceof JsonObject) {
JsonObject p = (JsonObject) parent;
p.add(optKey, child);
}
if (parent instanceof JsonArray) {
JsonArray p = (JsonArray) parent;
p.add(child);
}
}
private void genMetadata() { private void genMetadata() {
String oskey = "UNKNOWN"; String oskey = "UNKNOWN";
if (dtm instanceof ProgramDataTypeManager) { if (dtm instanceof ProgramDataTypeManager) {
@ -154,20 +155,21 @@ public class IsfDataTypeWriter {
oskey = metaData.get("Compiler ID"); oskey = metaData.get("Compiler ID");
if (metaData.containsKey("PDB Loaded")) { if (metaData.containsKey("PDB Loaded")) {
os = gson.toJsonTree(new IsfWinOS(metaData)); os = gson.toJsonTree(new IsfWinOS(metaData));
} } else if (metaData.containsKey("Executable Format")) {
else if (metaData.containsKey("Executable Format")) {
if (metaData.get("Executable Format").contains("ELF")) { if (metaData.get("Executable Format").contains("ELF")) {
oskey = "linux"; oskey = "linux";
os = gson.toJsonTree(new IsfLinuxOS(gson, metaData)); os = gson.toJsonTree(new IsfLinuxOS(gson, metaData));
} }
} }
metadata.addProperty("format", "6.2.0"); if (metadata instanceof JsonObject) {
metadata.add("producer", producer); ((JsonObject) metadata).addProperty("format", "6.2.0");
metadata.add(oskey, os); }
add(metadata, "producer", producer);
add(metadata, oskey, os);
} }
} }
private void genSymbols() { private void genSymbols(TaskMonitor monitor) {
if (!skipSymbols && dtm instanceof ProgramDataTypeManager) { if (!skipSymbols && dtm instanceof ProgramDataTypeManager) {
ProgramDataTypeManager pgmDtm = (ProgramDataTypeManager) dtm; ProgramDataTypeManager pgmDtm = (ProgramDataTypeManager) dtm;
Program program = pgmDtm.getProgram(); Program program = pgmDtm.getProgram();
@ -194,18 +196,15 @@ public class IsfDataTypeWriter {
Symbol symbol = iterator.next(); Symbol symbol = iterator.next();
symbolToJson(imageBase, symbolTable, linkages, map, symbol); symbolToJson(imageBase, symbolTable, linkages, map, symbol);
} }
} } else {
else {
for (Address addr : requestedAddresses) { for (Address addr : requestedAddresses) {
Symbol[] symsFromAddr = Symbol[] symsFromAddr = symbolTable.getSymbols(addr.add(imageBase.getOffset()));
symbolTable.getSymbols(addr.add(imageBase.getOffset()));
for (Symbol symbol : symsFromAddr) { for (Symbol symbol : symsFromAddr) {
symbolToJson(imageBase, symbolTable, linkages, map, symbol); symbolToJson(imageBase, symbolTable, linkages, map, symbol);
} }
} }
} }
} } else {
else {
for (String key : requestedSymbols) { for (String key : requestedSymbols) {
SymbolIterator iter = symbolTable.getSymbols(key); SymbolIterator iter = symbolTable.getSymbols(key);
while (iter.hasNext()) { while (iter.hasNext()) {
@ -215,33 +214,29 @@ public class IsfDataTypeWriter {
} }
} }
for (Entry<String, JsonObject> entry : map.entrySet()) { for (Entry<String, JsonObject> entry : map.entrySet()) {
symbols.add(entry.getKey(), entry.getValue()); add(symbols, entry.getKey(), entry.getValue());
} }
for (Entry<String, JsonObject> entry : map.entrySet()) { for (Entry<String, JsonObject> entry : map.entrySet()) {
if (entry.getKey().startsWith("_")) { if (entry.getKey().startsWith("_")) {
String nu = entry.getKey().substring(1); String nu = entry.getKey().substring(1);
if (symbols.get(nu) == null) { add(symbols, nu, entry.getValue());
symbols.add(nu, entry.getValue());
}
} }
} }
} }
} }
private void genTypes(TaskMonitor monitor) private void genTypes(TaskMonitor monitor) throws CancelledException, IOException {
throws CancelledException, IOException {
if (skipTypes) { if (skipTypes) {
return; return;
} }
Map<String, DataType> map = new HashMap<>(); Map<String, DataType> map = new HashMap<>();
if (requestedDataTypes.isEmpty()) { if (requestedDataTypes.isEmpty()) {
dtm.getAllDataTypes(requestedDataTypes); dtm.getAllDataTypes(requestedDataTypes);
baseTypes.add("pointer", getTree(new IsfTypedefPointer())); addSingletons();
baseTypes.add("undefined", getTree(new IsfTypedefPointer()));
} }
monitor.initialize(requestedDataTypes.size()); monitor.initialize(requestedDataTypes.size());
for (DataType dataType : requestedDataTypes) { for (DataType dataType : requestedDataTypes) {
String key = dataType.getName(); String key = dataType.getPathName();
map.put(key, dataType); map.put(key, dataType);
} }
@ -260,10 +255,9 @@ public class IsfDataTypeWriter {
private void processMap(Map<String, DataType> map, List<String> keylist, TaskMonitor monitor) private void processMap(Map<String, DataType> map, List<String> keylist, TaskMonitor monitor)
throws CancelledException, IOException { throws CancelledException, IOException {
JsonObject obj = new JsonObject(); JsonObject obj = new JsonObject();
int cnt = 0; monitor.setMaximum(keylist.size());
for (String key : keylist) { for (String key : keylist) {
DataType dataType = map.get(key); DataType dataType = map.get(key);
monitor.checkCancelled();
if (key.contains(".conflict")) { if (key.contains(".conflict")) {
continue; continue;
} }
@ -272,36 +266,29 @@ public class IsfDataTypeWriter {
continue; continue;
} }
if (dataType instanceof FunctionDefinition) { if (dataType instanceof FunctionDefinition) {
// Would be nice to support this in the futere, but Volatility does not // Would be nice to support this in the future, but Volatility does not
//typedefs.add(dataType.getName(), obj); add(functions, dataType.getPathName(), obj);
} } else if (IsfUtilities.isBaseDataType(dataType)) {
else if (IsfUtilities.isBaseDataType(dataType)) { add(baseTypes, dataType.getPathName(), obj);
baseTypes.add(dataType.getName(), obj); } else if (dataType instanceof TypeDef) {
}
else if (dataType instanceof TypeDef) {
DataType baseDataType = ((TypeDef) dataType).getBaseDataType(); DataType baseDataType = ((TypeDef) dataType).getBaseDataType();
if (IsfUtilities.isBaseDataType(baseDataType)) { if (IsfUtilities.isBaseDataType(baseDataType)) {
baseTypes.add(dataType.getName(), obj); add(baseTypes, dataType.getPathName(), obj);
} } else if (baseDataType instanceof Enum) {
else if (baseDataType instanceof Enum) { add(enums, dataType.getPathName(), obj);
enums.add(dataType.getName(), obj); } else {
} add(userTypes, dataType.getPathName(), obj);
else {
userTypes.add(dataType.getName(), obj);
} }
} else if (dataType instanceof Enum) {
add(enums, dataType.getPathName(), obj);
} else if (dataType instanceof Composite) {
add(userTypes, dataType.getPathName(), obj);
} }
else if (dataType instanceof Enum) { monitor.increment();
enums.add(dataType.getName(), obj);
}
else if (dataType instanceof Composite) {
userTypes.add(dataType.getName(), obj);
}
monitor.setProgress(++cnt);
} }
} }
private void symbolToJson(Address imageBase, SymbolTable symbolTable, private void symbolToJson(Address imageBase, SymbolTable symbolTable, Map<String, Symbol> linkages,
Map<String, Symbol> linkages,
Map<String, JsonObject> map, Symbol symbol) { Map<String, JsonObject> map, Symbol symbol) {
String key = symbol.getName(); String key = symbol.getName();
Address address = symbol.getAddress(); Address address = symbol.getAddress();
@ -313,9 +300,12 @@ public class IsfDataTypeWriter {
sym.addProperty("linkage_name", linkage.getName()); sym.addProperty("linkage_name", linkage.getName());
sym.addProperty("address", linkage.getAddress().getOffset()); sym.addProperty("address", linkage.getAddress().getOffset());
} }
} } else {
else { if (address.getAddressSpace().equals(imageBase.getAddressSpace())) {
sym.addProperty("address", address.subtract(imageBase)); sym.addProperty("address", address.subtract(imageBase));
} else {
sym.addProperty("address", address.getOffset());
}
} }
map.put(symbol.getName(), sym); map.put(symbol.getName(), sym);
if (!symbol.isPrimary()) { if (!symbol.isPrimary()) {
@ -332,8 +322,12 @@ public class IsfDataTypeWriter {
gson.toJson(obj, writer); gson.toJson(obj, writer);
} }
JsonObject getObjectForDataType(DataType dt, TaskMonitor monitor) protected void addSingletons() {
throws IOException, CancelledException { add(baseTypes, "pointer", getTree(newTypedefPointer(null)));
add(baseTypes, "undefined", getTree(newTypedefPointer(null)));
}
protected JsonObject getObjectForDataType(DataType dt, TaskMonitor monitor) throws IOException, CancelledException {
IsfObject isf = getIsfObject(dt, monitor); IsfObject isf = getIsfObject(dt, monitor);
if (isf != null) { if (isf != null) {
JsonObject jobj = (JsonObject) getTree(isf); JsonObject jobj = (JsonObject) getTree(isf);
@ -344,26 +338,27 @@ public class IsfDataTypeWriter {
} }
/** /**
* Writes the data type as ISF JSON using the underlying writer. For now, ignoring top-level * Writes the data type as ISF JSON using the underlying writer. For now,
* bit-fields and function defs as unsupported by ISF. Typedefs really deserve their own * ignoring top-level bit-fields and function defs as unsupported by ISF.
* category, but again unsupported. * Typedefs really deserve their own category, but again unsupported.
* *
* @param dt the data type to write as ISF JSON * @param dt the data type to write as ISF JSON
* @param monitor the task monitor * @param monitor the task monitor
* @throws IOException if there is an exception writing the output * @throws IOException if there is an exception writing the output
*/ */
private IsfObject getIsfObject(DataType dt, TaskMonitor monitor) protected IsfObject getIsfObject(DataType dt, TaskMonitor monitor) throws IOException, CancelledException {
throws IOException, CancelledException {
if (dt == null) { if (dt == null) {
Msg.error(this, "Shouldn't get here - null datatype passed"); throw new IOException("Null datatype passed to getIsfObject");
return null;
} }
if (dt instanceof FactoryDataType) { if (dt instanceof FactoryDataType) {
Msg.error(this, "Factory data types may not be written - type: " + dt); Msg.error(this, "Factory data types may not be written - type: " + dt);
} }
if (dt instanceof Pointer || dt instanceof Array || dt instanceof BitFieldDataType) { if (dt instanceof BitFieldDataType) {
Msg.error(this, "BitField data types may not be written - type: " + dt);
}
if (dt instanceof Pointer || dt instanceof Array) {
IsfObject type = getObjectDataType(IsfUtilities.getBaseDataType(dt)); IsfObject type = getObjectDataType(IsfUtilities.getBaseDataType(dt));
IsfObject obj = new IsfTypedObject(dt, type); IsfObject obj = newTypedObject(dt, type);
return obj; return obj;
} }
@ -377,41 +372,33 @@ public class IsfDataTypeWriter {
if (dt instanceof Dynamic dynamic) { if (dt instanceof Dynamic dynamic) {
DataType rep = dynamic.getReplacementBaseType(); DataType rep = dynamic.getReplacementBaseType();
return rep == null ? null : getIsfObject(rep, monitor); return rep == null ? null : getIsfObject(rep, monitor);
} } else if (dt instanceof TypeDef typedef) {
else if (dt instanceof TypeDef typedef) {
return getObjectTypeDef(typedef, monitor); return getObjectTypeDef(typedef, monitor);
} } else if (dt instanceof Composite composite) {
else if (dt instanceof Composite composite) {
return new IsfComposite(composite, this, monitor); return new IsfComposite(composite, this, monitor);
} } else if (dt instanceof Enum enumm) {
else if (dt instanceof Enum enumm) {
return new IsfEnum(enumm); return new IsfEnum(enumm);
} } else if (dt instanceof BuiltInDataType builtin) {
else if (dt instanceof BuiltInDataType builtin) {
return new IsfBuiltIn(builtin); return new IsfBuiltIn(builtin);
} } else if (dt instanceof BitFieldDataType) {
else if (dt instanceof BitFieldDataType) {
// skip - not hit // skip - not hit
} } else if (dt instanceof FunctionDefinition) { /// FAIL
else if (dt instanceof FunctionDefinition) { ///FAIL
// skip - not hit // skip - not hit
} } else if (dt.equals(DataType.DEFAULT)) {
else if (dt.equals(DataType.DEFAULT)) {
// skip - not hit // skip - not hit
} } else {
else {
Msg.warn(this, "Unable to write datatype. Type unrecognized: " + dt.getClass()); Msg.warn(this, "Unable to write datatype. Type unrecognized: " + dt.getClass());
} }
return null; return null;
} }
private IsfObject resolve(DataType dt) { public IsfObject resolve(DataType dt) {
if (resolved.containsKey(dt)) { if (resolved.containsKey(dt)) {
return resolved.get(dt); return resolved.get(dt);
} }
DataType resolvedType = resolvedTypeMap.get(dt.getName()); DataType resolvedType = resolvedTypeMap.get(dt.getPathName());
if (resolvedType != null) { if (resolvedType != null) {
if (resolvedType.isEquivalent(dt)) { if (resolvedType.isEquivalent(dt)) {
return resolved.get(dt); // skip equivalent type with same name as a resolved type return resolved.get(dt); // skip equivalent type with same name as a resolved type
@ -425,31 +412,32 @@ public class IsfDataTypeWriter {
} }
} }
} }
Msg.warn(this, "WARNING! conflicting data type names: " + dt.getPathName() + Msg.warn(this,
" - " + resolvedType.getPathName()); "WARNING! conflicting data type names: " + dt.getPathName() + " - " + resolvedType.getPathName());
return resolved.get(dt); return resolved.get(dt);
} }
resolvedTypeMap.put(dt.getName(), dt); resolvedTypeMap.put(dt.getPathName(), dt);
return null; return null;
} }
private void clearResolve(String typedefName, DataType baseType) { private void clearResolve(String typedefName, DataType baseType) {
if (baseType instanceof Composite || baseType instanceof Enum) { if (baseType instanceof Composite || baseType instanceof Enum) {
// auto-typedef generated with composite and enum // auto-typedef generated with composite and enum
if (typedefName.equals(baseType.getName())) { if (typedefName.equals(baseType.getPathName())) {
resolvedTypeMap.remove(typedefName); resolvedTypeMap.remove(typedefName);
return; return;
} }
} }
// Inherited from DataTypeWriter (logic lost to time): // Inherited from DataTypeWriter (logic lost to time):
// A comment explaining the special 'P' case would be helpful!! Smells like fish. // A comment explaining the special 'P' case would be helpful!! Smells like
// fish.
else if (baseType instanceof Pointer && typedefName.startsWith("P")) { else if (baseType instanceof Pointer && typedefName.startsWith("P")) {
DataType dt = ((Pointer) baseType).getDataType(); DataType dt = ((Pointer) baseType).getDataType();
if (dt instanceof TypeDef) { if (dt instanceof TypeDef) {
dt = ((TypeDef) dt).getBaseDataType(); dt = ((TypeDef) dt).getBaseDataType();
} }
if (dt instanceof Composite && dt.getName().equals(typedefName.substring(1))) { if (dt instanceof Composite && dt.getPathName().equals(typedefName.substring(1))) {
// auto-pointer-typedef generated with composite // auto-pointer-typedef generated with composite
resolvedTypeMap.remove(typedefName); resolvedTypeMap.remove(typedefName);
return; return;
@ -469,13 +457,11 @@ public class IsfDataTypeWriter {
int elementLen = replacementBaseType.getLength(); int elementLen = replacementBaseType.getLength();
if (elementLen > 0) { if (elementLen > 0) {
int elementCnt = (component.getLength() + elementLen - 1) / elementLen; int elementCnt = (component.getLength() + elementLen - 1) / elementLen;
return new IsfDynamicComponent(dynamic, type, elementCnt); return newIsfDynamicComponent(dynamic, type, elementCnt);
} }
Msg.error(this, Msg.error(this, dynamic.getClass().getSimpleName() + " returned bad replacementBaseType: "
dynamic.getClass().getSimpleName() + + replacementBaseType.getClass().getSimpleName());
" returned bad replacementBaseType: " +
replacementBaseType.getClass().getSimpleName());
} }
} }
return null; return null;
@ -492,7 +478,7 @@ public class IsfDataTypeWriter {
return getObjectDataType(dataType, -1); return getObjectDataType(dataType, -1);
} }
private IsfObject getObjectDataType(DataType dataType, int componentOffset) { public IsfObject getObjectDataType(DataType dataType, int componentOffset) {
if (dataType == null) { if (dataType == null) {
return new IsfDataTypeNull(); return new IsfDataTypeNull();
} }
@ -509,9 +495,9 @@ public class IsfDataTypeWriter {
IsfObject baseObject = getObjectDataType(IsfUtilities.getBaseDataType(dataType)); IsfObject baseObject = getObjectDataType(IsfUtilities.getBaseDataType(dataType));
return new IsfDataTypeTypeDef(dataType, baseObject); return new IsfDataTypeTypeDef(dataType, baseObject);
} }
if (dataType.getName().contains(".conflict")) { if (dataType.getPathName().contains(".conflict")) {
if (!deferredKeys.contains(dataType.getName())) { if (!deferredKeys.contains(dataType.getPathName())) {
deferredKeys.add(dataType.getName()); deferredKeys.add(dataType.getPathName());
} }
} }
return new IsfDataTypeDefault(dataType); return new IsfDataTypeDefault(dataType);
@ -522,27 +508,21 @@ public class IsfDataTypeWriter {
* *
* @throws CancelledException if the action is cancelled by the user * @throws CancelledException if the action is cancelled by the user
*/ */
private IsfObject getObjectTypeDef(TypeDef typeDef, TaskMonitor monitor) protected IsfObject getObjectTypeDef(TypeDef typeDef, TaskMonitor monitor) throws CancelledException {
throws CancelledException {
//UNVERIFIED
DataType dataType = typeDef.getDataType(); DataType dataType = typeDef.getDataType();
String typedefName = typeDef.getDisplayName(); String typedefName = typeDef.getPathName();
String dataTypeName = dataType.getDisplayName();
if (IsfUtilities.isIntegral(typedefName, dataTypeName)) {
return new IsfTypedefIntegral(typeDef);
}
DataType baseType = typeDef.getBaseDataType(); DataType baseType = typeDef.getDataType();
try { try {
if (baseType instanceof BuiltInDataType builtin) { if (baseType instanceof BuiltInDataType builtin) {
return new IsfTypedefBase(typeDef); return newTypedefBase(typeDef);
} }
if (!(baseType instanceof Pointer)) { if (!(baseType instanceof Pointer)) {
return getIsfObject(dataType, monitor); IsfObject isfObject = getIsfObject(dataType, monitor);
return newTypedefUser(typeDef, isfObject);
} }
return new IsfTypedefPointer(); return newTypedefPointer(typeDef);
} } catch (Exception e) {
catch (Exception e) {
Msg.error(this, "TypeDef error: " + e); Msg.error(this, "TypeDef error: " + e);
} }
clearResolve(typedefName, baseType); clearResolve(typedefName, baseType);
@ -550,11 +530,7 @@ public class IsfDataTypeWriter {
return null; return null;
} }
public JsonElement getTree(Object obj) { public void requestAddress(String key) throws IOException {
return gson.toJsonTree(obj);
}
public void requestAddress(String key) {
if (dtm instanceof ProgramDataTypeManager pgmDtm) { if (dtm instanceof ProgramDataTypeManager pgmDtm) {
try { try {
Address address = pgmDtm.getProgram().getMinAddress().getAddress(key); Address address = pgmDtm.getProgram().getMinAddress().getAddress(key);
@ -563,9 +539,8 @@ public class IsfDataTypeWriter {
return; return;
} }
requestedAddresses.add(address); requestedAddresses.add(address);
} } catch (AddressFormatException e) {
catch (AddressFormatException e) { throw new IOException("Bad address format: " + key);
e.printStackTrace();
} }
} }
} }
@ -578,24 +553,6 @@ public class IsfDataTypeWriter {
requestedSymbols.add(symbol); requestedSymbols.add(symbol);
} }
public void requestType(String path) {
requestedTypes.add(path);
DataType dataType = dtm.getDataType(path);
if (dataType == null) {
Msg.error(this, path + " not found");
return;
}
requestedDataTypes.add(dataType);
}
public void requestType(DataType dataType) {
if (dataType == null) {
Msg.error(this, dataType + " not found");
return;
}
requestedDataTypes.add(dataType);
}
public JsonWriter getWriter() { public JsonWriter getWriter() {
return writer; return writer;
} }
@ -605,16 +562,6 @@ public class IsfDataTypeWriter {
return baseWriter.toString(); return baseWriter.toString();
} }
public void close() {
try {
writer.flush();
writer.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
public void setSkipSymbols(boolean val) { public void setSkipSymbols(boolean val) {
skipSymbols = val; skipSymbols = val;
} }
@ -623,7 +570,28 @@ public class IsfDataTypeWriter {
skipTypes = val; skipTypes = val;
} }
public void setStrict(boolean val) { public IsfTypedefBase newTypedefBase(TypeDef typeDef) {
STRICT = val; return new IsfTypedefBase(typeDef);
} }
// public IsfTypedefIntegral newTypedefIntegral(TypeDef typeDef) {
// return new IsfTypedefIntegral(typeDef);
// }
public IsfTypedefPointer newTypedefPointer(TypeDef typeDef) {
return new IsfTypedefPointer(typeDef);
}
public IsfObject newTypedefUser(TypeDef typeDef, IsfObject object) {
return object;
}
public IsfTypedObject newTypedObject(DataType dt, IsfObject type) {
return new IsfTypedObject(dt, type);
}
public IsfObject newIsfDynamicComponent(Dynamic dynamic, IsfObject type, int elementCnt) {
return new IsfDynamicComponent(dynamic, type, elementCnt);
}
} }

View file

@ -17,13 +17,14 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.Dynamic; import ghidra.program.model.data.Dynamic;
public class IsfDynamicComponent implements IsfObject { public class IsfDynamicComponent extends AbstractIsfObject {
public String kind; public String kind;
public Integer count; public Integer count;
public IsfObject subtype; public IsfObject subtype;
public IsfDynamicComponent(Dynamic dynamicType, IsfObject type, int elementCnt) { public IsfDynamicComponent(Dynamic dynamicType, IsfObject type, int elementCnt) {
super(dynamicType);
kind = "array"; kind = "array";
subtype = type; subtype = type;
count = elementCnt; count = elementCnt;

View file

@ -19,13 +19,14 @@ import com.google.gson.JsonObject;
import ghidra.program.model.data.Enum; import ghidra.program.model.data.Enum;
public class IsfEnum implements IsfObject { public class IsfEnum extends AbstractIsfObject {
public Integer size; public Integer size;
public String base; public String base;
public JsonObject constants = new JsonObject(); public JsonObject constants = new JsonObject();
public IsfEnum(Enum enumm) { public IsfEnum(Enum enumm) {
super(enumm);
size = enumm.getLength(); size = enumm.getLength();
base = "int"; base = "int";
String[] names = enumm.getNames(); String[] names = enumm.getNames();

View file

@ -15,11 +15,14 @@
*/ */
package ghidra.program.model.data.ISF; package ghidra.program.model.data.ISF;
public class IsfFunction implements IsfObject { import ghidra.program.model.data.FunctionDefinition;
public class IsfFunction extends AbstractIsfObject {
public String kind; public String kind;
public IsfFunction() { public IsfFunction(FunctionDefinition def) {
super(def);
kind = "function"; kind = "function";
} }

View file

@ -18,14 +18,15 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
import ghidra.program.model.data.FunctionDefinition; import ghidra.program.model.data.FunctionDefinition;
public class IsfFunctionPointer implements IsfObject { public class IsfFunctionPointer extends AbstractIsfObject {
public String kind; public String kind;
public IsfObject subtype; public IsfObject subtype;
public IsfFunctionPointer(FunctionDefinition def, DataType dt) { public IsfFunctionPointer(FunctionDefinition def, DataType dt) {
super(def);
kind = "pointer"; kind = "pointer";
subtype = new IsfFunction(); subtype = new IsfFunction(def);
//TODO? //TODO?
} }

View file

@ -17,6 +17,6 @@ package ghidra.program.model.data.ISF;
public interface IsfObject { public interface IsfObject {
// EMPTY by design // EMPTY
} }

View file

@ -0,0 +1,32 @@
/* ###
* 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.program.model.data.ISF;
import ghidra.program.model.data.Pointer;
public class IsfPointer implements IsfObject {
public Integer size;
public String kind;
public String endian;
public IsfPointer(Pointer ptr) {
size = ptr.hasLanguageDependantLength() ? -1 : IsfUtilities.getLength(ptr);
kind = "pointer";
endian = IsfUtilities.getEndianness(ptr);
}
}

View file

@ -0,0 +1,30 @@
/* ###
* 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.program.model.data.ISF;
public class IsfSetting implements IsfObject {
public String name;
public String kind;
public String value;
public IsfSetting(String name, Object value) {
this.name = name;
this.value = value.toString();
this.kind = value instanceof String ? "string" : "long";
}
}

View file

@ -17,15 +17,16 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.DataType; import ghidra.program.model.data.DataType;
public class IsfTypedObject implements IsfObject { public class IsfTypedObject extends AbstractIsfObject {
public String kind; public String kind;
public Integer size; public Integer size;
public IsfObject type; public IsfObject type;
public IsfTypedObject(DataType dt, IsfObject typeObj) { public IsfTypedObject(DataType dt, IsfObject typeObj) {
super(dt);
kind = IsfUtilities.getKind(dt); kind = IsfUtilities.getKind(dt);
size = dt.getLength(); size = dt.hasLanguageDependantLength() ? -1 : dt.getLength();
type = typeObj; type = typeObj;
} }

View file

@ -18,18 +18,17 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.BuiltInDataType; import ghidra.program.model.data.BuiltInDataType;
import ghidra.program.model.data.TypeDef; import ghidra.program.model.data.TypeDef;
public class IsfTypedefBase implements IsfObject { public class IsfTypedefBase extends AbstractIsfObject {
public Integer size; public Integer size;
public String kind; public String kind;
public Boolean signed;
public String endian; public String endian;
public IsfTypedefBase(TypeDef typeDef) { public IsfTypedefBase(TypeDef typeDef) {
super(typeDef);
BuiltInDataType builtin = (BuiltInDataType) typeDef.getBaseDataType(); BuiltInDataType builtin = (BuiltInDataType) typeDef.getBaseDataType();
size = typeDef.getLength(); size = typeDef.getLength();
kind = IsfUtilities.getBuiltInKind(builtin); kind = IsfUtilities.getBuiltInKind(builtin);
signed = IsfUtilities.getSigned(typeDef);
endian = IsfUtilities.getEndianness(typeDef); endian = IsfUtilities.getEndianness(typeDef);
} }

View file

@ -17,11 +17,12 @@ package ghidra.program.model.data.ISF;
import ghidra.program.model.data.TypeDef; import ghidra.program.model.data.TypeDef;
public class IsfTypedefIntegral implements IsfObject { public class IsfTypedefIntegral extends AbstractIsfObject {
public Integer size; public Integer size;
public IsfTypedefIntegral(TypeDef td) { public IsfTypedefIntegral(TypeDef td) {
super(td);
size = td.getLength(); size = td.getLength();
} }

View file

@ -15,21 +15,30 @@
*/ */
package ghidra.program.model.data.ISF; package ghidra.program.model.data.ISF;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.PointerDataType; import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.data.TypeDef;
public class IsfTypedefPointer implements IsfObject { public class IsfTypedefPointer extends AbstractIsfObject {
public Integer size; public Integer size;
public Boolean signed;
public String kind; public String kind;
public String endian; public String endian;
public IsfObject type;
public IsfTypedefPointer() { public IsfTypedefPointer(TypeDef typeDef) {
PointerDataType ptr = new PointerDataType(); super(typeDef);
size = ptr.getLength(); Pointer ptr;
signed = false; //IsfUtilities.getSigned(ptr); if (typeDef != null) {
kind = IsfUtilities.getBuiltInKind(ptr); ptr = (Pointer) typeDef.getBaseDataType();
}
else {
ptr = new PointerDataType();
}
size = ptr.hasLanguageDependantLength() ? -1 : ptr.getLength();
kind = "typedef";
endian = IsfUtilities.getEndianness(ptr); endian = IsfUtilities.getEndianness(ptr);
type = new IsfPointer(ptr);
} }
} }

View file

@ -15,19 +15,19 @@
*/ */
package ghidra.program.model.data.ISF; package ghidra.program.model.data.ISF;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.TypeDef; import ghidra.program.model.data.TypeDef;
public class IsfTypedefUser implements IsfObject { public class IsfTypedefUser extends AbstractIsfObject {
public Integer size; public Integer size;
public String kind; public String kind;
public IsfObject type; public IsfObject type;
public IsfTypedefUser(TypeDef typeDef, IsfObject typeObj) { public IsfTypedefUser(TypeDef typeDef, IsfObject typeObj) {
DataType baseType = typeDef.getBaseDataType(); super(typeDef);
size = typeDef.getLength(); size = typeDef.getLength();
kind = IsfUtilities.getKind(baseType); kind = "typedef";
//kind = IsfUtilities.getKind(baseType);
type = typeObj; type = typeObj;
} }

View file

@ -20,46 +20,6 @@ import ghidra.program.model.data.Enum;
public class IsfUtilities { public class IsfUtilities {
// list of Ghidra built-in type names which correspond to C primitive types
private static String[] INTEGRAL_TYPES = { "char", "short", "int", "long", "long long",
"__int64", "float", "double", "long double", "void" };
private static String[] INTEGRAL_MODIFIERS =
{ "signed", "unsigned", "const", "static", "volatile", "mutable", };
public static boolean isIntegral(String typedefName, String basetypeName) {
for (String type : INTEGRAL_TYPES) {
if (typedefName.equals(type)) {
return true;
}
}
boolean endsWithIntegralType = false;
for (String type : INTEGRAL_TYPES) {
if (typedefName.endsWith(" " + type)) {
endsWithIntegralType = true;
break;
}
}
boolean containsIntegralModifier = false;
for (String modifier : INTEGRAL_MODIFIERS) {
if (typedefName.indexOf(modifier + " ") >= 0 ||
typedefName.indexOf(" " + modifier) >= 0) {
return true;
}
}
if (endsWithIntegralType && containsIntegralModifier) {
return true;
}
if (typedefName.endsWith(" " + basetypeName)) {
return containsIntegralModifier;
}
return false;
}
public static DataType getBaseDataType(DataType dt) { public static DataType getBaseDataType(DataType dt) {
while (dt != null) { while (dt != null) {
if (dt instanceof Array) { if (dt instanceof Array) {
@ -117,7 +77,7 @@ public class IsfUtilities {
return "enum"; return "enum";
} }
if (dt instanceof TypeDef) { if (dt instanceof TypeDef) {
return "base"; //"typedef"; return "typedef";
} }
if (dt instanceof FunctionDefinition) { if (dt instanceof FunctionDefinition) {
return "function"; return "function";
@ -133,7 +93,7 @@ public class IsfUtilities {
public static String getBuiltInKind(BuiltInDataType dt) { public static String getBuiltInKind(BuiltInDataType dt) {
if (dt instanceof AbstractIntegerDataType) { if (dt instanceof AbstractIntegerDataType) {
return dt.getLength() == 1 ? "char" : "int"; return dt.getName();
} }
if (dt instanceof AbstractFloatDataType) { if (dt instanceof AbstractFloatDataType) {
return "float"; return "float";
@ -145,7 +105,7 @@ public class IsfUtilities {
return "char"; // "string"; return "char"; // "string";
} }
if (dt instanceof PointerDataType) { if (dt instanceof PointerDataType) {
return "void"; //"pointer"; return "pointer";
} }
if (dt instanceof VoidDataType) { if (dt instanceof VoidDataType) {
return "void"; return "void";
@ -185,11 +145,48 @@ public class IsfUtilities {
return dt.getLength(); return dt.getLength();
} }
public static Boolean getSigned(DataType dt) {
return dt.getDataOrganization().isSignedChar();
}
public static String getEndianness(DataType dt) { public static String getEndianness(DataType dt) {
return dt.getDataOrganization().isBigEndian() ? "big" : "little"; return dt.getDataOrganization().isBigEndian() ? "big" : "little";
} }
// // list of Ghidra built-in type names which correspond to C primitive types
// private static String[] INTEGRAL_TYPES = { "char", "short", "int", "long", "long long",
// "__int64", "float", "double", "long double", "void" };
//
// private static String[] INTEGRAL_MODIFIERS =
// { "signed", "unsigned", "const", "static", "volatile", "mutable", };
//
// public static boolean isIntegral(String typedefName, String basetypeName) {
// for (String type : INTEGRAL_TYPES) {
// if (typedefName.equals(type)) {
// return true;
// }
// }
//
// boolean endsWithIntegralType = false;
// for (String type : INTEGRAL_TYPES) {
// if (typedefName.endsWith(" " + type)) {
// endsWithIntegralType = true;
// break;
// }
// }
// boolean containsIntegralModifier = false;
// for (String modifier : INTEGRAL_MODIFIERS) {
// if (typedefName.indexOf(modifier + " ") >= 0 ||
// typedefName.indexOf(" " + modifier) >= 0) {
// return true;
// }
// }
//
// if (endsWithIntegralType && containsIntegralModifier) {
// return true;
// }
//
// if (typedefName.endsWith(" " + basetypeName)) {
// return containsIntegralModifier;
// }
//
// return false;
// }
} }

View file

@ -389,7 +389,6 @@ src/main/help/help/topics/MemoryMapPlugin/images/MoveMemory.png||GHIDRA||||END|
src/main/help/help/topics/MemoryMapPlugin/images/SetImageBaseDialog.png||GHIDRA||||END| src/main/help/help/topics/MemoryMapPlugin/images/SetImageBaseDialog.png||GHIDRA||||END|
src/main/help/help/topics/MemoryMapPlugin/images/SplitMemoryBlock.png||GHIDRA||||END| src/main/help/help/topics/MemoryMapPlugin/images/SplitMemoryBlock.png||GHIDRA||||END|
src/main/help/help/topics/Misc/Appendix.htm||GHIDRA||||END| src/main/help/help/topics/Misc/Appendix.htm||GHIDRA||||END|
src/main/help/help/topics/Misc/Tips.htm||NONE||||END|
src/main/help/help/topics/Misc/Welcome_to_Ghidra_Help.htm||GHIDRA||||END| src/main/help/help/topics/Misc/Welcome_to_Ghidra_Help.htm||GHIDRA||||END|
src/main/help/help/topics/Navigation/Navigation.htm||GHIDRA||||END| src/main/help/help/topics/Navigation/Navigation.htm||GHIDRA||||END|
src/main/help/help/topics/Navigation/images/GoToDialog.png||GHIDRA||||END| src/main/help/help/topics/Navigation/images/GoToDialog.png||GHIDRA||||END|

View file

@ -37,6 +37,8 @@
<LI><A href="#binary">Raw Bytes</A></LI> <LI><A href="#binary">Raw Bytes</A></LI>
<LI><A href="#xml">XML Export Format</A></LI> <LI><A href="#xml">XML Export Format</A></LI>
<LI><A href="#sarif">SARIF Export Format</A></LI>
</UL> </UL>
<H2>Export Action</H2> <H2>Export Action</H2>
@ -414,6 +416,18 @@
XML Options are identical the <A href= XML Options are identical the <A href=
"help/topics/ImporterPlugin/importer.htm#xml_options">XML Importer Options</A>.</I></P> "help/topics/ImporterPlugin/importer.htm#xml_options">XML Importer Options</A>.</I></P>
</BLOCKQUOTE> </BLOCKQUOTE>
<H3><A name="sarif"/><A name="Options_SARIF"/>SARIF</H3>
<BLOCKQUOTE>
<P>The SARIF Exporter creates SARIF files that conform to Ghidra's Program DTD. You can
re-import files in this format using the <A href=
"help/topics/ImporterPlugin/importer.htm">SARIF Importer</A>.</P>
<P><A name="sarif_options"></A> <I><IMG alt="" border="0" src="help/shared/note.png">The
SARIF Options are identical the <A href=
"help/topics/ImporterPlugin/importer.htm#sarif_options">SARIF Importer Options</A>.</I></P>
</BLOCKQUOTE>
</BLOCKQUOTE> </BLOCKQUOTE>
<P class="relatedtopic">Related Topics:</P> <P class="relatedtopic">Related Topics:</P>

View file

@ -51,6 +51,7 @@
<LI>Raw Binary</LI> <LI>Raw Binary</LI>
<LI>Relocatable Object Module Format (OMF)</LI> <LI>Relocatable Object Module Format (OMF)</LI>
<LI>XML Input Format</LI> <LI>XML Input Format</LI>
<LI>SARIF Input Format</LI>
</UL> </UL>
</BLOCKQUOTE> </BLOCKQUOTE>
@ -680,6 +681,16 @@
Names</A>.</P> Names</A>.</P>
</BLOCKQUOTE> </BLOCKQUOTE>
</BLOCKQUOTE> </BLOCKQUOTE>
<H3>SARIF Options <A name="sarif_options"><A name="Options_SARIF_Input_Format"/></A></H3>
<BLOCKQUOTE>
<P>The SARIF format is used to load from a SARIF formatted file. The options are simply
switches for which types of program information to import and are identical to the options
specified above for XML.</P>
</BLOCKQUOTE>
</BLOCKQUOTE> </BLOCKQUOTE>
<H2><A name="Library_Paths"></A>Library Search Path</H2> <H2><A name="Library_Paths"></A>Library Search Path</H2>

View file

@ -64,8 +64,12 @@ import ghidra.util.task.*;
public class ExporterDialog extends DialogComponentProvider implements AddressFactoryService { public class ExporterDialog extends DialogComponentProvider implements AddressFactoryService {
private static final String XML_WARNING = private static final String XML_WARNING =
" Warning: XML is lossy and intended only for transfering data to external tools. " + " Warning: XML is lossy and intended only for transfering data to external tools. " +
"GZF is the recommended format for saving and sharing program data."; "GZF is the recommended format for saving and sharing program data.";
private static final String SARIF_WARNING =
" Warning: SARIF is lossy and intended only for transfering data to external tools. " +
"GZF is the recommended format for saving and sharing program data.";
private static String lastUsedExporterName = GzfExporter.NAME; // default to GZF first time private static String lastUsedExporterName = GzfExporter.NAME; // default to GZF first time
@ -394,6 +398,9 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa
if (getSelectedExporter().getName().contains("XML")) { if (getSelectedExporter().getName().contains("XML")) {
setStatusText(XML_WARNING); setStatusText(XML_WARNING);
} }
if (getSelectedExporter().getName().contains("SARIF")) {
setStatusText(SARIF_WARNING);
}
setOkEnabled(true); setOkEnabled(true);
} }

View file

@ -470,7 +470,7 @@ public class CodeManagerTest extends AbstractGenericTest {
Instruction inst = listing.getInstructionAt(addr(0x1100)); Instruction inst = listing.getInstructionAt(addr(0x1100));
inst.setProperty("Numbers", 12); inst.setProperty("Numbers", 12);
PropertyMap map = listing.getPropertyMap("Numbers"); PropertyMap<?> map = listing.getPropertyMap("Numbers");
assertNotNull(map); assertNotNull(map);
inst.setProperty("FavoriteColor", new SaveableColor(Palette.RED)); inst.setProperty("FavoriteColor", new SaveableColor(Palette.RED));

View file

@ -0,0 +1 @@
MODULE FILE LICENSE: lib/java-sarif-2.1.jar MIT

View file

@ -0,0 +1,36 @@
/* ###
* 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.
*/
apply from: "$rootProject.projectDir/gradle/distributableGhidraModule.gradle"
apply from: "$rootProject.projectDir/gradle/javaProject.gradle"
apply from: "$rootProject.projectDir/gradle/jacocoProject.gradle"
apply from: "$rootProject.projectDir/gradle/javaTestProject.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Features Sarif'
dependencies {
api project(':Base')
api project(':Debugger-isf')
//api "javax.activation:activation-1.1.1"
api "com.contrastsecurity.sarif:java-sarif-2.1"
}
test {
// temporary to prevent test from running when building
// specify a pattern that doesn't match any test files.
include "dontruntests"
}

View file

@ -0,0 +1,6 @@
##VERSION: 2.0
Module.manifest||GHIDRA||||END|
data/ExtensionPoint.manifest||GHIDRA||||END|
src/main/help/help/TOC_Source.xml||GHIDRA||||END|
src/main/help/help/topics/Sarif/SARIF.htm||GHIDRA||||END|
src/main/java/sarif/DEVNOTES.txt||GHIDRA||||END|

View file

@ -0,0 +1,2 @@
RunHandler
ResultHandler

View file

@ -0,0 +1,56 @@
<?xml version='1.0' encoding='ISO-8859-1' ?>
<!--
This is an XML file intended to be parsed by the Ghidra help system. It is loosely based
upon the JavaHelp table of contents document format. The Ghidra help system uses a
TOC_Source.xml file to allow a module with help to define how its contents appear in the
Ghidra help viewer's table of contents. The main document (in the Base module)
defines a basic structure for the
Ghidra table of contents system. Other TOC_Source.xml files may use this structure to insert
their files directly into this structure (and optionally define a substructure).
In this document, a tag can be either a <tocdef> or a <tocref>. The former is a definition
of an XML item that may have a link and may contain other <tocdef> and <tocref> children.
<tocdef> items may be referred to in other documents by using a <tocref> tag with the
appropriate id attribute value. Using these two tags allows any module to define a place
in the table of contents system (<tocdef>), which also provides a place for
other TOC_Source.xml files to insert content (<tocref>).
During the help build time, all TOC_Source.xml files will be parsed and validated to ensure
that all <tocref> tags point to valid <tocdef> tags. From these files will be generated
<module name>_TOC.xml files, which are table of contents files written in the format
desired by the JavaHelp system. Additionally, the generated files will be merged together
as they are loaded by the JavaHelp system. In the end, when displaying help in the Ghidra
help GUI, there will be one table of contents that has been created from the definitions in
all of the modules' TOC_Source.xml files.
Tags and Attributes
<tocdef>
-id - the name of the definition (this must be unique across all TOC_Source.xml files)
-text - the display text of the node, as seen in the help GUI
-target** - the file to display when the node is clicked in the GUI
-sortgroup - this is a string that defines where a given node should appear under a given
parent. The string values will be sorted by the JavaHelp system using
a javax.text.RulesBasedCollator. If this attribute is not specified, then
the text of attribute will be used.
<tocref>
-id - The id of the <tocdef> that this reference points to
**The URL for the target is relative and should start with 'help/topics'. This text is
used by the Ghidra help system to provide a universal starting point for all links so that
they can be resolved at runtime, across modules.
-->
<tocroot>
<tocref id="Program Annotation">
<tocdef id="SARIF" sortgroup="q" text="SARIF" target="help/topics/Sarif/SARIF.htm" >
</tocdef>
</tocref>
</tocroot>

View file

@ -0,0 +1,81 @@
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
<HTML>
<HEAD>
<META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<TITLE>Static Analysis Results Interchange Format (SARIF)</TITLE>
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
</HEAD>
<BODY lang="EN-US">
<H1><A name="Using_SARIF_Files"></A>Using SARIF Files</H1>
<P>SARIF is an OASIS standard for exchanging the results of static analysis performed against
a target executable. While not a perfect match for exchanging Ghidra program analysis results,
it has at least some level of community acceptance and support within the reverse engineering
communities at large. SARIF can be created in any number of ways, but, within Ghidra, SARIF
creation is done by means of any exporter. As with all of our exporters, a dialog appears when
you request an export, with an options panel for selecting which features you would like to export.
Currently, we support bookmarks, code, comments, data types, defined data, entry points, equates,
external libraries, functions, memory maps, properties, references, registers, relocations,
symbols, and program trees. </P>
<P>SARIF files can be re-ingested in two ways. A matching importer uses the same options to
create a new program or add features to an existing one. The process is probably lossy,
although efforts have been made to re-create exported programs with some fidelity. Known issues
are documented in the DEVNOTES file. The second way to ingest SARIF files is to configure a tool
with the SarifPlugin. The plugin provides a single "Read File" toolbar action. After selecting
a file, the SARIF results are displayed in table format, with associated ingest actions applicable
to a table selection. The features provide by the SARIF importer and exporter all share the action
"Add To Program".</P>
<H1><A name="Custom_SARIF_Handlers"></A>Writing Custom SARIF Handlers</H1>
<P>While the main SarifProgramResultHandler class handles the majority of program-derived
information used on import/export, there are many occasions where you might want to apply the
results of some external analysis to a Ghidra program. The "Features Sarif" project contains
templates (in the form of abstract classes) for custom handlers: SarifResultHandler.java and
SarifRunHandler.java. Both handler types extend ExtensionPoint and are discovered automatically
when the a file is read by the SarifPlugin.</P>
<P>Per-result handlers are used to populate a table displayed to the user and to associate
actions with a column in the table. The "getKey" method returns the name for a column, and the
"getActionName" a name for the action to be taken. When the user selects that action (in this case,
"Commit"), the table provider executes the program task specified by "getTask". In this example,
the task grabs the selected rows from the table and, for each row, applies the return type in the
column "return_type" to the address in the column "address".</P>
<P>A more complicated use case might involve the "parse" method, which is called for every result.
The default "handle" method takes anything returned by the "parse" method, creates key-value pairs
(stored as a map, but...) using "getKey" and the value returned, and adds them to a list of results
stored in the data frame. These can be retrieved programmatically later or processed immediately.
For example, the SarifPropertyResultHandler looks for results with "AdditionalProperties" labelled
either "viewer/table/xxx" or "listing/[comment, highlight, bookmark]". Items in the second category
are applied immediately to the current program. Items in the first category are added to the table
under column "xxx".</P>
<P> A third and significantly more complicated example is the ProgramResultHandler, which overrides
the "handle" method. This handler converts the set of "AdditionalProperties" into a key-value map.
The map is added to a list of results for the data frame, but also converted to a map of lists based
on the result's "RuleId". The frame ultimately accrues a map of list of maps, keyed on "RuleId".
Its "Add to Program" task takes each per-rule list and applies them to the program using the values
stored in the per-result maps.</P>
<P>A final example, the SarifGraphRunHandler, is a per-run handler and is generally called only once
(unless the SARIF files contains multiple runs). This example retrieves a SARIF Graph from the run,
converts it to a Ghidra graph object, and displays it. Controls for how and when SARIF graphs are
displayed are stored under Edit->Tool Options->Graph->Sarif.</P>
<P class="relatedtopic">Related Topics:</P>
<UL>
<LI><A href="help/topics/ImporterPlugin/importer.htm">Importers</A></LI>
<LI><A href="help/topics/ExporterPlugin/importer.htm">Exporters</A></LI>
</UL>
<P>&nbsp;</P>
</BODY>
</HTML>

View file

@ -0,0 +1,13 @@
Random notes:
1. Symbols require a pre- and post-function pass, pre- to guarantee the correct naming of globals
including functions and libraries and post- to guarantee namespaces have already been created
for locals
Code differences from export/re-import:
1. There may be missing parameter datatypes for parameters in a FunctionDefinition used inside a structure or union.
2. Datatypes like "RTTIBaseDescriptor *32 _((image-base-relative)) *32 _((image-base-relative))" are not handled correctly.
3. Modified/multiple ProgramTrees will not be imported correctly. Appears to be no way to fix this with the current API.

View file

@ -0,0 +1,289 @@
/* ###
* 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 sarif;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.contrastsecurity.sarif.Location;
import com.contrastsecurity.sarif.LogicalLocation;
import com.contrastsecurity.sarif.Result;
import com.contrastsecurity.sarif.SarifSchema210;
import docking.widgets.table.ObjectSelectedListener;
import ghidra.app.plugin.core.colorizer.ColorizingService;
import ghidra.app.services.GraphDisplayBroker;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.BookmarkManager;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.service.graph.AttributedGraph;
import ghidra.service.graph.EmptyGraphType;
import ghidra.service.graph.GraphDisplay;
import ghidra.service.graph.GraphDisplayOptions;
import ghidra.util.Msg;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.GraphException;
import resources.ResourceManager;
import sarif.handlers.SarifResultHandler;
import sarif.handlers.SarifRunHandler;
import sarif.managers.ProgramSarifMgr;
import sarif.model.SarifDataFrame;
import sarif.view.ImageArtifactDisplay;
import sarif.view.SarifResultsTableProvider;
/**
* Controller for handling interactions between the SARIF log file and Ghidra
*/
public class SarifController implements ObjectSelectedListener<Map<String, Object>> {
private SarifPlugin plugin;
private Program program;
private ColorizingService coloringService;
private BookmarkManager bookmarkManager;
private ProgramSarifMgr programManager;
private Set<SarifResultsTableProvider> providers = new HashSet<>();
public Set<ImageArtifactDisplay> artifacts = new HashSet<>();
public Set<GraphDisplay> graphs = new HashSet<>();
public Set<SarifResultHandler> getSarifResultHandlers() {
Set<SarifResultHandler> set = new HashSet<>();
set.addAll(ClassSearcher.getInstances(SarifResultHandler.class));
return set;
}
public Set<SarifRunHandler> getSarifRunHandlers() {
Set<SarifRunHandler> set = new HashSet<>();
set.addAll(ClassSearcher.getInstances(SarifRunHandler.class));
return set;
}
public SarifController(Program program, SarifPlugin plugin) {
this.program = program;
this.plugin = plugin;
this.coloringService = plugin.getTool().getService(ColorizingService.class);
this.programManager = new ProgramSarifMgr(program);
}
public SarifController(ProgramSarifMgr manager) {
this.program = null;
this.plugin = null;
this.coloringService = null; // plugin.getTool().getService(ColorizingService.class);
this.programManager = manager;
}
public void dispose() {
Set<SarifResultsTableProvider> copyProviders = new HashSet<>();
copyProviders.addAll(providers);
for (SarifResultsTableProvider p : copyProviders) {
p.dispose();
}
Set<ImageArtifactDisplay> copyArtifacts = new HashSet<>();
copyArtifacts.addAll(artifacts);
for (ImageArtifactDisplay a : copyArtifacts) {
a.dispose();
}
for (GraphDisplay g : graphs) {
g.close();
}
}
public void showTable(boolean makeVisible) {
for (SarifResultsTableProvider p : providers) {
p.setVisible(makeVisible);
}
}
public void showTable(String logName, SarifSchema210 sarif) {
SarifDataFrame df = new SarifDataFrame(sarif, this, false);
SarifResultsTableProvider provider = new SarifResultsTableProvider(logName, this.plugin, this, df);
provider.filterTable.addSelectionListener(this);
provider.addToTool();
provider.setVisible(true);
provider.setTitle(logName);
if (!providers.contains(provider)) {
providers.add(provider);
}
}
public void showImage(String key, BufferedImage img) {
if (plugin.displayArtifacts()) {
ImageArtifactDisplay display = new ImageArtifactDisplay(plugin.getTool(), key, "Sarif Parse", img);
display.setVisible(true);
artifacts.add(display);
}
}
public void showGraph(AttributedGraph graph) {
try {
GraphDisplayBroker service = this.plugin.getTool().getService(GraphDisplayBroker.class);
boolean append = plugin.appendToGraph();
GraphDisplay display = service.getDefaultGraphDisplay(append, null);
GraphDisplayOptions graphOptions = new GraphDisplayOptions(new EmptyGraphType());
graphOptions.setMaxNodeCount(plugin.getGraphSize());
if (plugin.displayGraphs()) {
display.setGraph(graph, graphOptions, graph.getDescription(), append, null);
graphs.add(display);
}
} catch (GraphException | CancelledException e) {
Msg.error(this, "showGraph failed " + e.getMessage());
}
}
/**
* If a results has "listing/<something>" in a SARIF result, this handles
* defining our custom API for those
*
* @param log
* @param result
* @param key
* @param value
*/
public void handleListingAction(Result result, String key, Object value) {
List<Address> addrs = getListingAddresses(result);
for (Address addr : addrs) {
switch (key) {
case "comment":
/* @formatter:off
* docs/GhidraAPI_javadoc/api/constant-values.html#ghidra.program.model.listing.CodeUnit
* EOL_COMMENT 0
* PRE_COMMENT 1
* POST_COMMENT 2
* PLATE_COMMENT 3
* REPEATABLE_COMMENT 4
* @formatter:on
*/
String comment = (String) value;
getProgram().getListing().setComment(addr, CodeUnit.PLATE_COMMENT, comment);
break;
case "highlight":
Color color = Color.decode((String) value);
coloringService.setBackgroundColor(addr, addr, color);
break;
case "bookmark":
String bookmark = (String) value;
getProgram().getBookmarkManager().setBookmark(addr, "Sarif", result.getRuleId(), bookmark);
break;
}
}
}
public void colorBackground(AddressSetView set, Color color) {
coloringService.setBackgroundColor(set, color);
}
public void colorBackground(Address addr, Color color) {
coloringService.setBackgroundColor(addr, addr, color);
}
public Address longToAddress(Object lval) {
if (lval instanceof Long) {
return getProgram().getAddressFactory().getDefaultAddressSpace().getAddress((Long) lval);
}
return getProgram().getAddressFactory().getDefaultAddressSpace().getAddress((Integer) lval);
}
/**
* Get listing addresses associated with a result
*
* @param result
* @return
*/
public List<Address> getListingAddresses(Result result) {
List<Address> addrs = new ArrayList<>();
if (result.getLocations() != null && result.getLocations().size() > 0) {
List<Location> locations = result.getLocations();
for (Location loc : locations) {
Address addr = locationToAddress(loc);
if (addr != null) {
addrs.add(addr);
}
}
}
return addrs;
}
public Address locationToAddress(Location loc) {
if (loc.getPhysicalLocation() != null) {
return longToAddress(loc.getPhysicalLocation().getAddress().getAbsoluteAddress());
}
if (loc.getLogicalLocations() != null) {
Set<LogicalLocation> logicalLocations = loc.getLogicalLocations();
for (LogicalLocation logLoc : logicalLocations) {
switch (logLoc.getKind()) {
case "function":
String fname = logLoc.getName();
for (Function func : getProgram().getFunctionManager().getFunctions(true)) {
if (fname.equals(func.getName())) {
return func.getEntryPoint();
}
}
break;
default:
Msg.error(this, "Unknown logical location to handle: " + logLoc.toString());
}
}
}
return null;
}
@SuppressWarnings("unchecked")
@Override
public void objectSelected(Map<String, Object> row) {
if (row != null) {
if (row.containsKey("CodeFlows")) {
for (List<Address> flow : (List<List<Address>>) row.get("CodeFlows")) {
this.plugin.makeSelection(flow);
}
}
if (row.containsKey("Graphs")) {
for (AttributedGraph graph : (List<AttributedGraph>) row.get("Graphs")) {
this.showGraph(graph);
}
}
}
}
public void removeProvider(SarifResultsTableProvider provider) {
providers.remove(provider);
}
public ProgramSarifMgr getProgramSarifMgr() {
return programManager;
}
public Program getProgram() {
return program;
}
public void setProgram(Program program) {
this.program = program;
this.bookmarkManager = program.getBookmarkManager();
bookmarkManager.defineType("Sarif", ResourceManager.loadImage("images/peach_16.png"), Color.pink, 0);
}
}

View file

@ -0,0 +1,350 @@
/* ###
* 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 sarif;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import ghidra.app.plugin.core.analysis.AnalysisWorker;
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
import ghidra.app.util.Option;
import ghidra.app.util.OptionException;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.AbstractProgramLoader;
import ghidra.app.util.opinion.LoadException;
import ghidra.app.util.opinion.LoadSpec;
import ghidra.app.util.opinion.Loaded;
import ghidra.app.util.opinion.LoaderTier;
import ghidra.framework.model.DomainObject;
import ghidra.framework.model.Project;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.lang.CompilerSpecDescription;
import ghidra.program.model.lang.CompilerSpecNotFoundException;
import ghidra.program.model.lang.Endian;
import ghidra.program.model.lang.ExternalLanguageCompilerSpecQuery;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.LanguageCompilerSpecPair;
import ghidra.program.model.lang.LanguageDescription;
import ghidra.program.model.lang.LanguageNotFoundException;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.SarifObject;
import sarif.managers.ProgramInfo;
import sarif.managers.ProgramSarifMgr;
public class SarifLoader extends AbstractProgramLoader {
private static final String FILE_EXTENSION = SarifObject.SARIF ? ".sarif" : ".json";
public final static String SARIF_SRC_NAME = "SARIF Input Format";
@Override
public LoaderTier getTier() {
return LoaderTier.SPECIALIZED_TARGET_LOADER;
}
@Override
public int getTierPriority() {
return 50;
}
@Override
public boolean supportsLoadIntoProgram() {
return true;
}
@Override
public Collection<LoadSpec> findSupportedLoadSpecs(ByteProvider provider) throws IOException {
List<LoadSpec> loadSpecs = new ArrayList<>();
//
// Unusual Code Alert!: the parse() method below uses Processor to
// location processors
// by name when reading SARIF. The Processor class is not fully
// populated until the languages have been loaded.
//
getLanguageService();
ParseResult result = parse(provider);
ProgramInfo info = result.lastInfo;
if (info == null) {
return loadSpecs;
}
if (info.languageID != null) {// non-external language
// got a language ID, good...
try {
LanguageDescription languageDescription =
getLanguageService().getLanguageDescription(info.languageID);
boolean preferred = false;
if (info.compilerSpecID == null) {
// no compiler spec ID, try to pick "default" (embedded
// magic string!!! BAD)
for (CompilerSpecDescription csd : languageDescription.getCompatibleCompilerSpecDescriptions()) {
LanguageCompilerSpecPair pair = new LanguageCompilerSpecPair(
languageDescription.getLanguageID(), csd.getCompilerSpecID());
loadSpecs.add(new LoadSpec(this, 0, pair, preferred));
}
}
else {
// test existence; throw exception on failure
languageDescription.getCompilerSpecDescriptionByID(info.compilerSpecID);
// good, we know exactly what this is (make it preferred)
LanguageCompilerSpecPair pair =
new LanguageCompilerSpecPair(info.languageID, info.compilerSpecID);
preferred = true;
loadSpecs.add(new LoadSpec(this, 0, pair, preferred));
}
}
catch (CompilerSpecNotFoundException | LanguageNotFoundException lnfe) {
// ignore
// should fall into loadSpecs.isEmpty() case below
}
}
else if (info.processorName != null) {// external language
// no ID, look by processor/possibly endian
Integer size = extractSize(info.addressModel);
Endian endian = Endian.toEndian(info.endian);
ExternalLanguageCompilerSpecQuery broadQuery =
new ExternalLanguageCompilerSpecQuery(info.processorName,
info.getNormalizedExternalToolName(), endian, size, info.compilerSpecID);
List<LanguageCompilerSpecPair> pairs =
getLanguageService().getLanguageCompilerSpecPairs(broadQuery);
if (!pairs.isEmpty()) {
boolean preferred = false;
if (pairs.size() == 1) {
preferred = true;
}
for (LanguageCompilerSpecPair pair : pairs) {
loadSpecs.add(new LoadSpec(this, 0, pair, preferred));
}
}
}
if (loadSpecs.isEmpty() && provider.getName().endsWith(FILE_EXTENSION)) {
// just put 'em all in (give endianess preference)
List<LanguageDescription> languageDescriptions =
getLanguageService().getLanguageDescriptions(false);
for (LanguageDescription languageDescription : languageDescriptions) {
Collection<CompilerSpecDescription> compilerSpecDescriptions =
languageDescription.getCompatibleCompilerSpecDescriptions();
for (CompilerSpecDescription compilerSpecDescription : compilerSpecDescriptions) {
LanguageCompilerSpecPair pair =
new LanguageCompilerSpecPair(languageDescription.getLanguageID(),
compilerSpecDescription.getCompilerSpecID());
loadSpecs.add(new LoadSpec(this, 0, pair, false));
}
}
}
return loadSpecs;
}
private static Pattern ADDRESS_MODEL_PATTERN = Pattern.compile("(\\d+)-bit");
private Integer extractSize(String addressModel) {
if (addressModel != null) {
Matcher matcher = ADDRESS_MODEL_PATTERN.matcher(addressModel);
if (matcher.find()) {
return Integer.parseInt(matcher.group(1));
}
}
return null;
}
@Override
public String getPreferredFileName(ByteProvider provider) {
String name = provider.getName();
if (name.toLowerCase().endsWith(FILE_EXTENSION)) {
return name.substring(0, name.length() - FILE_EXTENSION.length());
}
return name;
}
@Override
protected List<Loaded<Program>> loadProgram(ByteProvider provider, String programName,
Project project, String programFolderPath, LoadSpec loadSpec, List<Option> options,
MessageLog log, Object consumer, TaskMonitor monitor)
throws IOException, LoadException, CancelledException {
//throw new RuntimeException("SARIF importer supports only 'Add To Program'");
LanguageCompilerSpecPair pair = loadSpec.getLanguageCompilerSpec();
Language importerLanguage = getLanguageService().getLanguage(pair.languageID);
CompilerSpec importerCompilerSpec =
importerLanguage.getCompilerSpecByID(pair.compilerSpecID);
ParseResult result = parse(provider);
Address imageBase = null;
if (result.lastInfo.imageBase != null) {
imageBase = importerLanguage.getAddressFactory().getAddress(result.lastInfo.imageBase);
}
Program prog = createProgram(provider, programName, imageBase, getName(), importerLanguage,
importerCompilerSpec, consumer);
List<Loaded<Program>> loadedList =
List.of(new Loaded<>(prog, programName, programFolderPath));
boolean success = false;
try {
success = doImport(result.lastSarifMgr, options, log, prog, monitor, false);
if (success) {
createDefaultMemoryBlocks(prog, importerLanguage, log);
return loadedList;
}
throw new LoadException("Failed to load");
}
finally {
if (!success) {
release(loadedList, consumer);
}
}
}
@Override
protected void loadProgramInto(ByteProvider provider, LoadSpec loadSpec,
List<Option> options, MessageLog log, Program prog, TaskMonitor monitor)
throws IOException, LoadException, CancelledException {
File file = provider.getFile();
doImport(new ProgramSarifMgr(prog, file), options, log, prog, monitor, true);
}
private boolean doImportWork(final ProgramSarifMgr mgr, final List<Option> options,
final MessageLog log, Program prog, TaskMonitor monitor,
final boolean isAddToProgram) throws LoadException {
boolean success = true;
try {
SarifProgramOptions sarifOptions = mgr.getOptions();
sarifOptions.setOptions(options);
sarifOptions.setAddToProgram(isAddToProgram);
mgr.read(prog, monitor);
success = true;
}
catch (Exception e) {
String message = "(empty)";
if (log != null && !"".equals(log.toString())) {
message = log.toString();
}
Msg.warn(this, "SARIF import exception, log: " + message, e);
throw new LoadException(e.getMessage());
}
return success;
}
private boolean doImport(final ProgramSarifMgr mgr, final List<Option> options,
final MessageLog log, Program prog, TaskMonitor monitor, final boolean isAddToProgram)
throws IOException {
if (!AutoAnalysisManager.hasAutoAnalysisManager(prog)) {
int txId = prog.startTransaction("SARIF Import");
try {
return doImportWork(mgr, options, log, prog, monitor, isAddToProgram);
}
finally {
prog.endTransaction(txId, true);
}
}
AutoAnalysisManager analysisMgr = AutoAnalysisManager.getAnalysisManager(prog);
try {
return analysisMgr.scheduleWorker(new AnalysisWorker() {
@Override
public String getWorkerName() {
return "SARIF Importer";
}
@Override
public boolean analysisWorkerCallback(Program program, Object workerContext,
TaskMonitor taskMonitor) throws Exception, CancelledException {
return doImportWork(mgr, options, log, program, taskMonitor, isAddToProgram);
}
}, null, false, monitor);
}
catch (CancelledException e) {
return false;
}
catch (InvocationTargetException e) {
Throwable cause = e.getCause();
if (cause instanceof IOException) {
throw (IOException) cause;
}
throw new RuntimeException(e);
}
catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private static class ParseResult {
final ProgramSarifMgr lastSarifMgr;
final ProgramInfo lastInfo;
ParseResult(ProgramSarifMgr lastSarifMgr, ProgramInfo lastInfo) {
this.lastSarifMgr = lastSarifMgr;
this.lastInfo = lastInfo;
}
}
private ParseResult parse(ByteProvider provider) {
try {
ProgramSarifMgr lastSarifMgr = new ProgramSarifMgr(provider);
ProgramInfo lastInfo = lastSarifMgr.getProgramInfo();
return new ParseResult(lastSarifMgr, lastInfo);
}
catch (Throwable e) {
// This can happen during the import process when this loader attempts to load
// a non-SARIF file (there really should be 2 methods, a speculative version and
// a version that expects no exception)
Msg.trace(this, "Unable to parse SARIF for " + provider.getName(), e);
return new ParseResult(null, null);
}
}
@Override
public List<Option> getDefaultOptions(ByteProvider provider, LoadSpec loadSpec,
DomainObject domainObject, boolean loadIntoProgram) {
return new SarifProgramOptions().getOptions(loadIntoProgram);
}
@Override
public String getName() {
return SARIF_SRC_NAME;
}
@Override
public String validateOptions(ByteProvider provider, LoadSpec loadSpec, List<Option> options, Program program) {
try {
new SarifProgramOptions().setOptions(options);
}
catch (OptionException e) {
return e.getMessage();
}
return null;
}
}

View file

@ -0,0 +1,250 @@
/* ###
* 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 sarif;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.Icon;
import com.contrastsecurity.sarif.SarifSchema210;
import com.google.gson.JsonSyntaxException;
import docking.action.builder.ActionBuilder;
import docking.tool.ToolConstants;
import docking.widgets.filechooser.GhidraFileChooser;
import ghidra.MiscellaneousPluginPackage;
import ghidra.app.events.ProgramActivatedPluginEvent;
import ghidra.app.events.ProgramClosedPluginEvent;
import ghidra.app.events.ProgramOpenedPluginEvent;
import ghidra.app.events.ProgramVisibilityChangePluginEvent;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.framework.options.Options;
import ghidra.framework.options.OptionsChangeListener;
import ghidra.framework.options.ToolOptions;
import ghidra.framework.plugintool.PluginEvent;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.Msg;
import ghidra.util.bean.opteditor.OptionsVetoException;
import resources.ResourceManager;
import sarif.io.SarifGsonIO;
import sarif.io.SarifIO;
//@formatter:off
@PluginInfo(
status = PluginStatus.RELEASED,
packageName = MiscellaneousPluginPackage.NAME,
category = PluginCategoryNames.ANALYSIS,
shortDescription = "Sarif Plugin.",
description = "From sarif parsing to DL modelling"
)
//@formatter:on
/**
* A {@link ProgramPlugin} for reading in sarif files
*/
public class SarifPlugin extends ProgramPlugin implements OptionsChangeListener {
public static final String NAME = "Sarif";
public static final Icon SARIF_ICON = ResourceManager.loadImage("images/peach_16.png");
private Map<Program, SarifController> sarifControllers;
private SarifIO io;
public SarifPlugin(PluginTool tool) {
super(tool);
this.sarifControllers = new HashMap<Program, SarifController>();
this.io = new SarifGsonIO();
}
@Override
protected void init() {
createActions();
initializeOptions();
}
public void readFile(File file) {
if (file != null) {
try {
showSarif(file.getName(), io.readSarif(file));
} catch (JsonSyntaxException | IOException e) {
Msg.showError(this, tool.getActiveWindow(), "File parse error", "Invalid Sarif File");
}
}
}
@Override
public void processEvent(PluginEvent event) {
super.processEvent(event);
Program eventProgram = null;
if (event instanceof ProgramActivatedPluginEvent) {
ProgramActivatedPluginEvent ev = (ProgramActivatedPluginEvent) event;
eventProgram = ev.getActiveProgram();
}
else if (event instanceof ProgramOpenedPluginEvent) {
ProgramOpenedPluginEvent ev = (ProgramOpenedPluginEvent) event;
eventProgram = ev.getProgram();
}
else if (event instanceof ProgramClosedPluginEvent) {
ProgramClosedPluginEvent ev = (ProgramClosedPluginEvent) event;
eventProgram = ev.getProgram();
}
else if (event instanceof ProgramClosedPluginEvent) {
ProgramClosedPluginEvent ev = (ProgramClosedPluginEvent) event;
eventProgram = ev.getProgram();
}
else if (event instanceof ProgramVisibilityChangePluginEvent) {
ProgramVisibilityChangePluginEvent ev = (ProgramVisibilityChangePluginEvent) event;
eventProgram = ev.getProgram();
}
SarifController controller = sarifControllers.get(eventProgram);
if (controller != null) {
if (event instanceof ProgramClosedPluginEvent) {
controller.dispose();
sarifControllers.remove(eventProgram, controller);
}
else if (event instanceof ProgramVisibilityChangePluginEvent) {
ProgramVisibilityChangePluginEvent ev = (ProgramVisibilityChangePluginEvent) event;
controller.showTable(ev.isProgramVisible());
}
else {
controller.showTable(true);
}
}
}
/**
* Ultimately both selections end up calling this to actually show something on
* the Ghidra gui
*
* @param logName
* @param sarif
*/
public void showSarif(String logName, SarifSchema210 sarif) {
currentProgram = getCurrentProgram();
if (currentProgram != null) {
if (!sarifControllers.containsKey(currentProgram)) {
SarifController controller = new SarifController(currentProgram, this);
sarifControllers.put(currentProgram, controller);
}
SarifController currentController = sarifControllers.get(currentProgram);
if (currentController != null) {
currentController.showTable(logName, sarif);
return;
}
}
Msg.showError(this, tool.getActiveWindow(), "File parse error", "No current program");
}
public void makeSelection(List<Address> addrs) {
AddressSet selection = new AddressSet();
for (Address addr : addrs) {
selection.add(addr);
}
this.setSelection(selection);
}
private void createActions() {
//@formatter:off
new ActionBuilder("Read", getName())
.menuPath("Sarif", "Read File")
.menuGroup("sarif", "1")
.enabledWhen(ctx -> getCurrentProgram() != null)
.onAction(e -> {
GhidraFileChooser chooser = new GhidraFileChooser(tool.getActiveWindow());
this.readFile(chooser.getSelectedFile());
})
.buildAndInstall(tool);
//@formatter:on
}
private void initializeOptions() {
ToolOptions options = tool.getOptions(ToolConstants.GRAPH_OPTIONS);
options.addOptionsChangeListener(this);
HelpLocation help = new HelpLocation(getName(), "Options");
Options sarifOptions = options.getOptions(NAME);
registerOptions(sarifOptions, help);
loadOptions(sarifOptions);
}
@Override
public void optionsChanged(ToolOptions options, String optionName, Object oldValue,
Object newValue) throws OptionsVetoException {
Options sarifOptions = options.getOptions(NAME);
loadOptions(sarifOptions);
}
public void registerOptions(Options options, HelpLocation help) {
options.setOptionsHelpLocation(help);
options.registerOption("Display Artifacts", displayArtifacts(), help,
"Display artifacts by default");
options.registerOption("Display Graphs", displayGraphs(), help,
"Display graphs by default");
options.registerOption("Max Graph Size", getGraphSize(), help,
"Maximum number of nodes per graph");
options.registerOption("Append Graphs", appendToGraph(), help,
"Append to existing graph");
}
public void loadOptions(Options options) {
displayArtifactsByDefault = options.getBoolean("Display Artifacts", displayArtifacts());
displayGraphsByDefault = options.getBoolean("Display Graphs", displayGraphs());
maxGraphSize = options.getInt("Max Graph Size", getGraphSize());
appendToCurrentGraph = options.getBoolean("Append Graphs", appendToGraph());
}
private boolean displayGraphsByDefault = false;
public boolean displayGraphs() {
return displayGraphsByDefault;
}
private boolean displayArtifactsByDefault = false;
public boolean displayArtifacts() {
return displayArtifactsByDefault;
}
private int maxGraphSize = 1000;
public int getGraphSize() {
return maxGraphSize;
}
private boolean appendToCurrentGraph = false;
public boolean appendToGraph() {
return appendToCurrentGraph;
}
}

View file

@ -0,0 +1,611 @@
/* ###
* 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 sarif;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.Option;
import ghidra.app.util.OptionException;
/**
* A class to hold SARIF options.
*
*/
public class SarifProgramOptions {
/**Flag to indicate reading/writing memory blocks*/
public final static long OPT_MEMORY_BLOCKS = 0x00000001L;
/**Flag to indicate reading/writing memory contents*/
public final static long OPT_MEMORY_CONTENTS = 0x00000002L;
/**Flag to indicate reading/writing instructions*/
public final static long OPT_CODE = 0x00000004L;
/**Flag to indicate reading/writing root*/
public final static long OPT_DATA = 0x00000008L;
/**Flag to indicate reading/writing symbols*/
public final static long OPT_SYMBOLS = 0x00000010L;
/**Flag to indicate reading/writing equates*/
public final static long OPT_EQUATES = 0x00000020L;
/**Flag to indicate reading/writing comments*/
public final static long OPT_COMMENTS = 0x00000040L;
/**Flag to indicate reading/writing properties*/
public final static long OPT_PROPERTIES = 0x00000080L;
/**Flag to indicate reading/writing trees*/
public final static long OPT_TREES = 0x00000100L;
/**Flag to indicate reading/writing empty program tree nodes*/
public final static long OPT_EMPTY_TREE_NODES = 0x00000200L;
/**Flag to indicate reading/writing references*/
public final static long OPT_REFERENCES = 0x00000400L;
/**Flag to indicate reading/writing functions*/
public final static long OPT_FUNCTIONS = 0x00000800L;
/**
* Used to signify that symbols should be overwritten when
* necessary. This value is not being included in
* the <code>ALL</code> constant.
*/
public final static long OVERWRITE_SYMBOLS = 0x20000000L;
/**
* Used to signify that references should be overwritten when
* necessary. This value is not being included in
* the <code>ALL</code> constant.
*/
public final static long OVERWRITE_REFS = 0x40000000L;
/**
* Used to signify that an existing program is being
* updated. This value is not being included in
* the <code>ALL</code> constant.
*/
public final static long ADD_2_PROG = 0x80000000L;
private boolean addToProgram = false;
private boolean memoryBlocks = true;
private boolean memoryContents = true;
private boolean overwriteMemoryConflicts = false;
private boolean instructions = true;
private boolean overwriteDataConflicts = true;
private boolean data = true;
private boolean symbols = true;
private boolean overwriteSymbolConflicts = true;
private boolean equates = true;
private boolean comments = true;
private boolean properties = true;
private boolean overwritePropertyConflicts = true;
private boolean bookmarks = true;
private boolean overwriteBookmarkConflicts = true;
private boolean trees = true;
private boolean references = true;
private boolean overwriteReferenceConflicts = true;
private boolean functions = true;
private boolean registers = true;
private boolean relocationTable = true;
private boolean entryPoints = true;
private boolean externalLibraries = true;
/**
* Returns an array of importer options representing
* the flags in this class.
* @param isAddToProgram if true then adding to existing program
* @return the array of importer options
*/
public List<Option> getOptions(boolean isAddToProgram) {
this.addToProgram = isAddToProgram;
ArrayList<Option> optionList = new ArrayList<>();
optionList.add(new Option("Memory Blocks", Boolean.valueOf(isMemoryBlocks())));
optionList.add(new Option("Memory Contents", Boolean.valueOf(isMemoryContents())));
if (isAddToProgram) {
optionList.add(new Option("Overwrite Memory Conflicts",
Boolean.valueOf(isOverwriteMemoryConflicts())));
}
optionList.add(new Option("Instructions", Boolean.valueOf(isInstructions())));
optionList.add(new Option("Data", Boolean.valueOf(isData())));
if (isAddToProgram) {
optionList.add(
new Option("Overwrite Data Conflicts", Boolean.valueOf(isOverwriteDataConflicts())));
}
optionList.add(new Option("Symbols", Boolean.valueOf(isSymbols())));
if (isAddToProgram) {
optionList.add(new Option("Overwrite Symbol Conflicts",
Boolean.valueOf(isOverwriteSymbolConflicts())));
}
optionList.add(new Option("Equates", Boolean.valueOf(isEquates())));
optionList.add(new Option("Comments", Boolean.valueOf(isComments())));
optionList.add(new Option("Properties", Boolean.valueOf(isProperties())));
if (isAddToProgram) {
optionList.add(new Option("Overwrite Property Conflicts",
Boolean.valueOf(isOverwritePropertyConflicts())));
}
optionList.add(new Option("Bookmarks", Boolean.valueOf(isBookmarks())));
if (isAddToProgram) {
optionList.add(new Option("Overwrite Bookmark Conflicts",
Boolean.valueOf(isOverwriteBookmarkConflicts())));
}
optionList.add(new Option("Trees", Boolean.valueOf(isTrees())));
optionList.add(new Option("References", Boolean.valueOf(isReferences())));
if (isAddToProgram) {
optionList.add(new Option("Overwrite Reference Conflicts",
Boolean.valueOf(isOverwriteReferenceConflicts())));
}
optionList.add(new Option("Functions", Boolean.valueOf(isFunctions())));
optionList.add(new Option("Registers", Boolean.valueOf(isRegisters())));
optionList.add(new Option("Relocation Table", Boolean.valueOf(isRelocationTable())));
optionList.add(new Option("Entry Points", Boolean.valueOf(isEntryPoints())));
optionList.add(new Option("External Libraries", Boolean.valueOf(isExternalLibraries())));
return optionList;
}
/**
* Sets the options. This method is not for defining the options, but
* rather for setting the values of options. If invalid options
* are passed in, then OptionException should be thrown.
* @param options the option values for SARIF
* @throws OptionException if invalid options are passed in
*/
public void setOptions(List<Option> options) throws OptionException {
for (Option option : options) {
String optName = option.getName();
Object optValue = option.getValue();
if (!(optValue instanceof Boolean)) {
throw new OptionException("Invalid type for option: " + optName);
}
boolean val = ((Boolean) optValue).booleanValue();
if (optName.equals("Memory Blocks")) {
setMemoryBlocks(val);
}
else if (optName.equals("Memory Contents")) {
setMemoryContents(val);
}
else if (optName.equals("Overwrite Memory Conflicts")) {
setOverwriteMemoryConflicts(val);
}
else if (optName.equals("Instructions")) {
setInstructions(val);
}
else if (optName.equals("Data")) {
setData(val);
}
else if (optName.equals("Overwrite Data Conflicts")) {
setOverwriteDataConflicts(val);
}
else if (optName.equals("Symbols")) {
setSymbols(val);
}
else if (optName.equals("Overwrite Symbol Conflicts")) {
setOverwriteSymbolConflicts(val);
}
else if (optName.equals("Equates")) {
setEquates(val);
}
else if (optName.equals("Comments")) {
setComments(val);
}
else if (optName.equals("Properties")) {
setProperties(val);
}
else if (optName.equals("Overwrite Property Conflicts")) {
setOverwritePropertyConflicts(val);
}
else if (optName.equals("Bookmarks")) {
setBookmarks(val);
}
else if (optName.equals("Overwrite Bookmark Conflicts")) {
setOverwriteBookmarkConflicts(val);
}
else if (optName.equals("Trees")) {
setTrees(val);
}
else if (optName.equals("References")) {
setReferences(val);
}
else if (optName.equals("Overwrite Reference Conflicts")) {
setOverwriteReferenceConflicts(val);
}
else if (optName.equals("Functions")) {
setFunctions(val);
}
else if (optName.equals("Registers")) {
setRegisters(val);
}
else if (optName.equals("Relocation Table")) {
setRelocationTable(val);
}
else if (optName.equals("Entry Points")) {
setEntryPoints(val);
}
else if (optName.equals("External Libraries")) {
setExternalLibraries(val);
}
else {
throw new OptionException("Unknown option: " + optName);
}
}
}
/**
* Returns true if importing to an existing program.
* Importing to an existing program creates a new
* set of potential conflicts. For example, memory block
* may collide. When this options is true, additional
* options are visible.
* @return true if importing to an existing program
*/
public boolean isAddToProgram() {
return addToProgram;
}
/**
* If true, then instructions should be read/written.
* @return true if instructions should be read/written
*/
public boolean isInstructions() {
return instructions;
}
/**
* If true, then comments should be read/written.
* @return true if comments should be read/written
*/
public boolean isComments() {
return comments;
}
/**
* If true, then root should be read/written.
* @return true if root should be read/written
*/
public boolean isData() {
return data;
}
/**
* If true, then equates should be read/written.
* @return true if equates should be read/written
*/
public boolean isEquates() {
return equates;
}
/**
* If true, then functions should be read/written.
* @return true if functions should be read/written
*/
public boolean isFunctions() {
return functions;
}
/**
* If true, then memory blocks should be read/written.
* @return true if memory blocks should be read/written
*/
public boolean isMemoryBlocks() {
return memoryBlocks;
}
/**
* If true, then memory contents should be read/written.
* @return true if memory contents should be read/written
*/
public boolean isMemoryContents() {
return memoryContents;
}
/**
* If true, then properties should be read/written.
* @return true if properties should be read/written
*/
public boolean isProperties() {
return properties;
}
/**
* If true, then references (memory, stack, external) should be read/written.
* @return true if references should be read/written
*/
public boolean isReferences() {
return references;
}
/**
* If true, then symbols should be read/written.
* @return true if symbols should be read/written
*/
public boolean isSymbols() {
return symbols;
}
/**
* If true, then program trees should be read/written.
* @return true if program trees should be read/written
*/
public boolean isTrees() {
return trees;
}
/**
* Sets instructions to be read/written.
* @param b true if instructions should read/written
*/
public void setInstructions(boolean b) {
instructions = b;
}
/**
* Sets comments to be read/written.
* @param b true if comments should read/written
*/
public void setComments(boolean b) {
comments = b;
}
/**
* Sets root to be read/written.
* @param b true if root should read/written
*/
public void setData(boolean b) {
data = b;
}
/**
* Sets equates to be read/written.
* @param b true if equates should read/written
*/
public void setEquates(boolean b) {
equates = b;
}
/**
* Sets functions to be read/written.
* @param b true if functions should read/written
*/
public void setFunctions(boolean b) {
functions = b;
}
/**
* Sets memory blocks to be read/written.
* @param b true if memory blocks should read/written
*/
public void setMemoryBlocks(boolean b) {
memoryBlocks = b;
}
/**
* Sets memory contents to be read/written.
* @param b true if memory contents should read/written
*/
public void setMemoryContents(boolean b) {
memoryContents = b;
}
/**
* Sets properties to be read/written.
* @param b true if properties should read/written
*/
public void setProperties(boolean b) {
properties = b;
}
/**
* Sets references to be read/written.
* @param b true if references should read/written
*/
public void setReferences(boolean b) {
references = b;
}
/**
* Sets symbols to be read/written.
* @param b true if symbols should read/written
*/
public void setSymbols(boolean b) {
symbols = b;
}
/**
* Sets program trees to be read/written.
* @param b true if program trees should read/written
*/
public void setTrees(boolean b) {
trees = b;
}
/**
* If true, then bookmarks should be read/written.
* @return true if bookmarks should be read/written
*/
public boolean isBookmarks() {
return bookmarks;
}
/**
* If true, then registers should be read/written.
* @return true if registers should be read/written
*/
public boolean isRegisters() {
return registers;
}
/**
* If true, then the relocation table should be read/written.
* @return true if the relocation table should be read/written
*/
public boolean isRelocationTable() {
return relocationTable;
}
/**
* Sets bookmarks to be read/written.
* @param b true if bookmarks should read/written
*/
public void setBookmarks(boolean b) {
bookmarks = b;
}
/**
* Sets registers to be read/written.
* @param b true if registers should read/written
*/
public void setRegisters(boolean b) {
registers = b;
}
/**
* Sets relocation tables to be read/written.
* @param b true if relocation table should read/written
*/
public void setRelocationTable(boolean b) {
relocationTable = b;
}
/**
* If true, then the entry points should be read/written.
* @return true if the entry points should be read/written
*/
public boolean isEntryPoints() {
return entryPoints;
}
/**
* If true, then the external libraries should be read/written.
* @return true if the external libraries should be read/written
*/
public boolean isExternalLibraries() {
return externalLibraries;
}
/**
* Sets entry points to be read/written.
* @param b true if entry points should read/written
*/
public void setEntryPoints(boolean b) {
entryPoints = b;
}
/**
* Sets external libraries to be read/written.
* @param b true if external libraries should read/written
*/
public void setExternalLibraries(boolean b) {
externalLibraries = b;
}
/**
* If true, then property conflicts will be overwritten.
* @return true if property conflicts will be overwritten
*/
public boolean isOverwritePropertyConflicts() {
return overwritePropertyConflicts;
}
/**
* If true, then bookmark conflicts will be overwritten.
* @return true if bookmark conflicts will be overwritten
*/
public boolean isOverwriteBookmarkConflicts() {
return overwriteBookmarkConflicts;
}
/**
* If true, then symbol conflicts will be overwritten.
* @return true if symbol conflicts will be overwritten
*/
public boolean isOverwriteSymbolConflicts() {
return overwriteSymbolConflicts;
}
/**
* If true, then reference conflicts will be overwritten.
* @return true if reference conflicts will be overwritten
*/
public boolean isOverwriteReferenceConflicts() {
return overwriteReferenceConflicts;
}
/**
* If true, then memory conflicts will be overwritten.
* @return true if memory conflicts will be overwritten
*/
public boolean isOverwriteMemoryConflicts() {
return overwriteMemoryConflicts;
}
/**
* If true, then root conflicts will be overwritten.
* @return true if root conflicts will be overwritten
*/
public boolean isOverwriteDataConflicts() {
return overwriteDataConflicts;
}
/**
* Sets bookmark conflicts to always be overwritten.
* @param b true if bookmark conflicts should always be overwritten
*/
public void setOverwriteBookmarkConflicts(boolean b) {
overwriteBookmarkConflicts = b;
}
/**
* Sets memory conflicts to always be overwritten.
* @param b true if memory conflicts should always be overwritten
*/
public void setOverwriteMemoryConflicts(boolean b) {
overwriteMemoryConflicts = b;
}
/**
* Sets root conflicts to always be overwritten.
* @param b true if root conflicts should always be overwritten
*/
public void setOverwriteDataConflicts(boolean b) {
overwriteDataConflicts = b;
}
/**
* Sets property conflicts to always be overwritten.
* @param b true if property conflicts should always be overwritten
*/
public void setOverwritePropertyConflicts(boolean b) {
overwritePropertyConflicts = b;
}
/**
* Sets reference conflicts to always be overwritten.
* @param b true if reference conflicts should always be overwritten
*/
public void setOverwriteReferenceConflicts(boolean b) {
overwriteReferenceConflicts = b;
}
/**
* Sets symbol conflicts to always be overwritten.
* @param b true if symbol conflicts should always be overwritten
*/
public void setOverwriteSymbolConflicts(boolean b) {
overwriteSymbolConflicts = b;
}
public void setAddToProgram(boolean addToProgram) {
this.addToProgram = addToProgram;
}
}

View file

@ -0,0 +1,72 @@
/* ###
* 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 sarif;
import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.bouncycastle.util.encoders.Base64;
import com.contrastsecurity.sarif.Artifact;
import com.contrastsecurity.sarif.ArtifactContent;
import com.contrastsecurity.sarif.ReportingDescriptor;
import com.contrastsecurity.sarif.ReportingDescriptorReference;
import com.contrastsecurity.sarif.Run;
import com.contrastsecurity.sarif.ToolComponent;
public class SarifUtils {
public static ByteArrayInputStream getArtifactContent(Artifact artifact) {
ArtifactContent content = artifact.getContents();
String b64 = content.getBinary();
byte[] decoded = Base64.decode(b64);
return new ByteArrayInputStream(decoded);
}
public static ReportingDescriptor getTaxaValue(ReportingDescriptorReference taxa, ToolComponent taxonomy) {
List<ReportingDescriptor> view = new ArrayList<>(taxonomy.getTaxa());
return view.get(taxa.getIndex().intValue());
}
public static ToolComponent getTaxonomy(ReportingDescriptorReference taxa, Set<ToolComponent> taxonomies) {
Object idx = taxa.getToolComponent().getIndex();
if (idx == null) {
List<ToolComponent> view = new ArrayList<>(taxonomies);
idx= taxa.getIndex();
return view.get(idx instanceof Long ? ((Long)idx).intValue() : (Integer) idx);
}
for (ToolComponent taxonomy : taxonomies) {
if (taxonomy.getName().equals(taxa.getToolComponent().getName())) {
return taxonomy;
}
}
return null;
}
public static List<String> getTaxonomyNames(Run sarifRun) {
List<String> names = new ArrayList<>();
Set<ToolComponent> taxonomies = sarifRun.getTaxonomies();
if (taxonomies != null) {
for (ToolComponent taxonomy : sarifRun.getTaxonomies()) {
names.add(taxonomy.getName());
}
}
return names;
}
}

View file

@ -0,0 +1,35 @@
/* ###
* 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 sarif.export;
import java.io.IOException;
import java.io.Writer;
import ghidra.program.model.data.ISF.AbstractIsfWriter;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public abstract class AbstractExtWriter extends AbstractIsfWriter {
public AbstractExtWriter(Writer baseWriter) throws IOException {
super(baseWriter);
STRICT = false;
}
@Override
protected abstract void genRoot(TaskMonitor monitor) throws CancelledException, IOException;
}

View file

@ -0,0 +1,92 @@
/* ###
* 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 sarif.export;
import java.io.File;
import java.io.IOException;
import java.util.List;
import ghidra.app.util.DomainObjectService;
import ghidra.app.util.Option;
import ghidra.app.util.OptionException;
import ghidra.app.util.exporter.Exporter;
import ghidra.app.util.exporter.ExporterException;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.SarifProgramOptions;
import sarif.managers.ProgramSarifMgr;
/**
* An implementation of exporter that creates
* an SARIF representation of the program.
*/
public class SarifExporter extends Exporter {
private SarifProgramOptions options = new SarifProgramOptions();
/**
* Constructs a new SARIF exporter.
*/
public SarifExporter() {
super("SARIF", "sarif", new HelpLocation("ExporterPlugin", "sarif"));
}
@Override
public List<Option> getOptions(DomainObjectService domainObjectService) {
if (options == null) {
options = new SarifProgramOptions();
}
return options.getOptions(false);
}
@Override
public void setOptions(List<Option> options) throws OptionException {
this.options.setOptions(options);
}
@Override
public boolean export(File file, DomainObject domainObj, AddressSetView addrSet, TaskMonitor monitor)
throws IOException, ExporterException {
log.clear();
if (!(domainObj instanceof Program)) {
log.appendMsg("Unsupported type: "+domainObj.getClass().getName());
return false;
}
Program program = (Program)domainObj;
if (addrSet == null) {
addrSet = program.getMemory();
}
ProgramSarifMgr mgr = new ProgramSarifMgr(program, file);
try {
log = mgr.write(program, addrSet, monitor, options);
}
catch (CancelledException e) {
throw new ExporterException("User cancelled SARIF export.");
}
options = null;
return true;
}
}

View file

@ -0,0 +1,123 @@
/* ###
* 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 sarif.export;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.address.AddressRangeIterator;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.ISF.IsfObject;
public class SarifObject implements IsfObject {
public static boolean SARIF = true;
protected JsonObject message;
protected String kind;
protected String level;
protected String ruleId;
protected JsonArray locations;
protected JsonObject properties;
protected JsonObject element;
public SarifObject(String key, String ruleKey, JsonElement element) {
if (SARIF) {
message = new JsonObject();
message.addProperty("text", key);
kind = "INFORMATIONAL";
level = "NONE";
ruleId = ruleKey;
properties = new JsonObject();
properties.add("additionalProperties", element);
} else {
this.element = (JsonObject) element;
this.element.addProperty("key", key);
this.element.addProperty("rule", ruleKey);
}
}
public SarifObject(String key, String ruleKey, JsonElement tree, Address min, Address max) {
this(key, ruleKey, tree);
if (min != null) {
writeLocations(min, max);
}
}
public SarifObject(String key, String ruleKey, JsonElement tree, AddressSetView body) {
this(key, ruleKey, tree);
if (body != null) {
writeLocations(body);
}
}
protected void writeLocations(Address min, Address max) {
if (SARIF) {
locations = new JsonArray();
JsonObject element = new JsonObject();
locations.add(element);
JsonObject ploc = new JsonObject();
element.add("physicalLocation", ploc);
JsonObject address = new JsonObject();
ploc.add("address", address);
address.addProperty("absoluteAddress", min.getOffset());
address.addProperty("length", max.subtract(min) + 1);
Address minAddress = min;
if (minAddress.getAddressSpace().getType() != AddressSpace.TYPE_RAM) {
JsonObject artifact = new JsonObject();
ploc.add("artifactLocation", artifact);
artifact.addProperty("uri", minAddress.toString());
}
}
else {
element.addProperty("startAddress", min.toString(true));
element.addProperty("stopAddress", max.toString(true));
}
}
protected void writeLocations(AddressSetView set) {
if (SARIF) {
locations = new JsonArray();
AddressRangeIterator addressRanges = set.getAddressRanges();
while (addressRanges.hasNext()) {
JsonObject element = new JsonObject();
locations.add(element);
AddressRange next = addressRanges.next();
JsonObject ploc = new JsonObject();
element.add("physicalLocation", ploc);
JsonObject address = new JsonObject();
ploc.add("address", address);
address.addProperty("absoluteAddress", next.getMinAddress().getOffset());
address.addProperty("length", next.getLength());
Address minAddress = next.getMinAddress();
if (minAddress.getAddressSpace().getType() != AddressSpace.TYPE_RAM) {
JsonObject artifact = new JsonObject();
ploc.add("artifactLocation", artifact);
artifact.addProperty("uri", minAddress.toString());
}
}
}
else {
element.addProperty("startAddress", set.getMinAddress().toString(true));
element.addProperty("stopAddress", set.getMaxAddress().toString(true));
}
}
}

View file

@ -0,0 +1,62 @@
/* ###
* 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 sarif.export;
import java.io.IOException;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import ghidra.program.model.data.ISF.AbstractIsfWriter;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.Task;
import ghidra.util.task.TaskMonitor;
public class SarifWriterTask extends Task {
protected AbstractIsfWriter writer;
protected JsonArray results;
public SarifWriterTask(String tag, AbstractIsfWriter writer, JsonArray results) {
super(tag, true, false, true);
this.writer = writer;
this.results = results;
}
@Override
public void run(TaskMonitor monitor) {
try {
try {
writer.getRootObject(monitor);
JsonArray res = writer.getResults();
for (JsonElement element : res) {
if (monitor.isCancelled()) {
break;
}
results.add(element);
}
} finally {
writer.close();
}
} catch (CancelledException e) {
// user cancelled; ignore
} catch (IOException e) {
Msg.error("Export Data Types Failed", "Error exporting Data Types: " + e);
return;
}
}
}

View file

@ -0,0 +1,39 @@
/* ###
* 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 sarif.export.bkmk;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.listing.Bookmark;
public class ExtBookmark implements IsfObject {
String name;
String comment;
String kind;
public ExtBookmark(Bookmark b) {
String category = b.getCategory();
String comment = b.getComment();
if (category != null && category.length() != 0) {
name = category;
}
if (comment != null && comment.length() != 0) {
this.comment = comment;
}
kind = b.getType().getTypeString();
}
}

View file

@ -0,0 +1,54 @@
/* ###
* 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 sarif.export.bkmk;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.listing.Bookmark;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.BookmarksSarifMgr;
public class SarifBookmarkWriter extends AbstractExtWriter {
private List<Bookmark> bookmarks = new ArrayList<>();
public SarifBookmarkWriter(List<Bookmark> target, Writer baseWriter) throws IOException {
super(baseWriter);
bookmarks = target;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genBookmarks(monitor);
root.add("bookmarks", objects);
}
private void genBookmarks(TaskMonitor monitor) throws CancelledException, IOException{
monitor.initialize(bookmarks.size());
for (Bookmark b : bookmarks) {
ExtBookmark isf = new ExtBookmark(b);
SarifObject sarif = new SarifObject(BookmarksSarifMgr.SUBKEY, BookmarksSarifMgr.KEY, getTree(isf), b.getAddress(), b.getAddress());
objects.add(getTree(sarif));
monitor.increment();
}
}
}

View file

@ -0,0 +1,26 @@
/* ###
* 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 sarif.export.code;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.data.ISF.IsfObject;
public class ExtCodeBlock implements IsfObject {
public ExtCodeBlock(AddressRange range) {
}
}

View file

@ -0,0 +1,31 @@
/* ###
* 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 sarif.export.code;
import generic.stl.Pair;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.listing.FlowOverride;
import ghidra.program.model.listing.Instruction;
public class ExtCodeOverride implements IsfObject {
String kind;
public ExtCodeOverride(Pair<Instruction, FlowOverride> pair) {
kind = pair.second.name();
}
}

View file

@ -0,0 +1,70 @@
/* ###
* 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 sarif.export.code;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import generic.stl.Pair;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.listing.FlowOverride;
import ghidra.program.model.listing.Instruction;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.CodeSarifMgr;
public class SarifCodeWriter extends AbstractExtWriter {
private List<AddressRange> blocks;
private List<Pair<Instruction, FlowOverride>> overrides;
public SarifCodeWriter(List<AddressRange> target0, List<Pair<Instruction, FlowOverride>> target1, Writer baseWriter) throws IOException {
super(baseWriter);
this.blocks = target0;
this.overrides = target1;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genCode(monitor);
genOverrides(monitor);
root.add("code", objects);
}
private void genCode(TaskMonitor monitor) throws CancelledException, IOException{
monitor.initialize(blocks.size());
for (AddressRange range : blocks) {
ExtCodeBlock isf = new ExtCodeBlock(range);
SarifObject sarif = new SarifObject(CodeSarifMgr.SUBKEY, CodeSarifMgr.KEY, getTree(isf), range.getMinAddress(), range.getMaxAddress());
objects.add(getTree(sarif));
monitor.increment();
}
}
private void genOverrides(TaskMonitor monitor) throws CancelledException, IOException{
monitor.initialize(overrides.size());
for (Pair<Instruction, FlowOverride> pair : overrides) {
Instruction inst = pair.first;
ExtCodeOverride isf = new ExtCodeOverride(pair);
SarifObject sarif = new SarifObject(CodeSarifMgr.SUBKEY2, CodeSarifMgr.KEY, getTree(isf), inst.getMinAddress(), inst.getMaxAddress());
objects.add(getTree(sarif));
monitor.increment();
}
}
}

View file

@ -0,0 +1,33 @@
/* ###
* 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 sarif.export.comments;
import generic.stl.Pair;
import ghidra.program.model.data.ISF.IsfObject;
public class ExtComment implements IsfObject {
String kind;
String value;
boolean standard;
public ExtComment(Pair<String, String> pair, boolean standard) {
kind = pair.first;
value = pair.second;
this.standard = standard;
}
}

View file

@ -0,0 +1,82 @@
/* ###
* 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 sarif.export.comments;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import generic.stl.Pair;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.CodeUnit;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.CommentsSarifMgr;
public class SarifCommentWriter extends AbstractExtWriter {
private List<Pair<CodeUnit, Pair<String, String>>> comments0;
private List<Pair<Address, Pair<String, String>>> comments1;
public SarifCommentWriter(List<Pair<CodeUnit, Pair<String, String>>> target, Writer baseWriter) throws IOException {
super(baseWriter);
this.comments0 = target;
}
public SarifCommentWriter(Writer baseWriter, List<Pair<Address, Pair<String, String>>> target) throws IOException {
super(baseWriter);
this.comments1 = target;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genComments0(monitor);
genComments1(monitor);
root.add("comments", objects);
}
private void genComments0(TaskMonitor monitor) throws CancelledException, IOException {
if (comments0 == null) {
return;
}
monitor.initialize(comments0.size());
for (Pair<CodeUnit, Pair<String, String>> pair : comments0) {
CodeUnit cu = pair.first;
ExtComment isf = new ExtComment(pair.second, true);
SarifObject sarif = new SarifObject(CommentsSarifMgr.SUBKEY, CommentsSarifMgr.KEY, getTree(isf), cu.getMinAddress(),
cu.getMaxAddress());
objects.add(getTree(sarif));
monitor.increment();
}
}
private void genComments1(TaskMonitor monitor) throws CancelledException, IOException {
if (comments1 == null) {
return;
}
monitor.initialize(comments1.size());
for (Pair<Address, Pair<String, String>> pair : comments1) {
Address addr = pair.first;
ExtComment isf = new ExtComment(pair.second, false);
SarifObject sarif = new SarifObject(CommentsSarifMgr.SUBKEY, CommentsSarifMgr.KEY, getTree(isf), addr, addr);
objects.add(getTree(sarif));
monitor.increment();
}
}
}

View file

@ -0,0 +1,63 @@
/* ###
* 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 sarif.export.data;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.ISF.IsfDataTypeWriter;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.Task;
import ghidra.util.task.TaskMonitor;
public class ExtDataTypeWriterTask extends Task {
private final DataTypeManager programDataTypeMgr;
private final List<DataType> dataTypeList;
private final File file;
public ExtDataTypeWriterTask(DataTypeManager programDataTypeMgr, List<DataType> dataTypeList, File file) {
super("Export Data Types", true, false, true);
this.programDataTypeMgr = programDataTypeMgr;
this.dataTypeList = dataTypeList;
this.file = file;
}
@Override
public void run(TaskMonitor monitor) {
try {
monitor.setMessage("Export to " + file.getName() + "...");
IsfDataTypeWriter dataTypeWriter = new ExtIsfDataTypeWriter(programDataTypeMgr, dataTypeList, new FileWriter(file));
try {
dataTypeWriter.getRootObject(monitor);
//dataTypeWriter.write(object);
} finally {
dataTypeWriter.close();
}
} catch (CancelledException e) {
// user cancelled; ignore
} catch (IOException e) {
Msg.error("Export Data Types Failed", "Error exporting Data Types: " + e);
return;
}
}
}

View file

@ -0,0 +1,37 @@
/* ###
* 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 sarif.export.data;
import ghidra.program.model.data.BitFieldDataType;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.ISF.IsfComponent;
import ghidra.program.model.data.ISF.IsfObject;
public class ExtIsfComponent extends IsfComponent {
Integer bitOffset;
Integer bitSize;
public ExtIsfComponent(DataTypeComponent component, IsfObject typeObj) {
super(component, typeObj);
if (component.isBitFieldComponent()) {
BitFieldDataType dt = (BitFieldDataType) component.getDataType();
bitOffset = dt.getBitOffset();
bitSize = dt.getBitSize();
}
}
}

View file

@ -0,0 +1,50 @@
/* ###
* 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 sarif.export.data;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.ISF.IsfComponent;
import ghidra.program.model.data.ISF.IsfComposite;
import ghidra.program.model.data.ISF.IsfDataTypeWriter;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.util.task.TaskMonitor;
public class ExtIsfComposite extends IsfComposite {
String packed;
Integer explicitPackingValue;
String alignment;
Integer explicitMinimumAlignment;
public ExtIsfComposite(Composite composite, IsfDataTypeWriter writer, TaskMonitor monitor) {
super(composite, writer, monitor);
name = composite.getName();
location = composite.getCategoryPath().getPath();
packed = Boolean.toString(composite.isPackingEnabled());
int epval = composite.getExplicitPackingValue();
explicitPackingValue = epval > 0 ? epval : null;
alignment = Integer.toHexString(composite.getAlignment());
int maval = composite.getExplicitMinimumAlignment();
explicitMinimumAlignment = maval > 0 ? maval : null;
}
@Override
protected IsfComponent getComponent(DataTypeComponent component, IsfObject type) {
return new ExtIsfComponent(component, type);
}
}

View file

@ -0,0 +1,144 @@
/* ###
* 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 sarif.export.data;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import ghidra.program.model.data.Array;
import ghidra.program.model.data.BitFieldDataType;
import ghidra.program.model.data.BuiltInDataType;
import ghidra.program.model.data.Composite;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.Dynamic;
import ghidra.program.model.data.Enum;
import ghidra.program.model.data.FactoryDataType;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.ISF.IsfBuiltIn;
import ghidra.program.model.data.ISF.IsfDataTypeWriter;
import ghidra.program.model.data.ISF.IsfEnum;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.data.ISF.IsfTypedObject;
import ghidra.program.model.data.ISF.IsfTypedefBase;
import ghidra.program.model.data.ISF.IsfTypedefPointer;
import ghidra.program.model.data.ISF.IsfUtilities;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class ExtIsfDataTypeWriter extends IsfDataTypeWriter {
public ExtIsfDataTypeWriter(DataTypeManager dtm, List<DataType> target, Writer baseWriter) throws IOException {
super(dtm, target, baseWriter);
STRICT = false;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
super.genRoot(monitor);
data.add("functions", functions);
}
/**
* Writes the root type as ISF JSON using the underlying writer. For now, ignoring top-level
* bit-fields and function defs as unsupported by ISF. Typedefs really deserve their own
* category, but again unsupported.
*
* @param dt the root type to write as ISF JSON
* @param monitor the task monitor
* @throws IOException if there is an exception writing the output
*/
@Override
protected IsfObject getIsfObject(DataType dt, TaskMonitor monitor)
throws IOException, CancelledException {
if (dt == null) {
throw new IOException("Null datatype passed to getIsfObject");
}
if (dt instanceof FactoryDataType) {
Msg.error(this, "Factory root types may not be written - type: " + dt);
}
if (dt instanceof BitFieldDataType) {
Msg.error(this, "BitField data types may not be written - type: " + dt);
}
if (dt instanceof Pointer || dt instanceof Array) {
IsfObject type = getObjectDataType(IsfUtilities.getBaseDataType(dt));
IsfObject obj = new ExtIsfTypedObject(dt, type);
return obj;
}
dt = dt.clone(dtm); // force resize/repack for target root organization
IsfObject res = resolve(dt);
if (res != null) {
return res;
}
if (dt instanceof Dynamic dynamic) {
DataType rep = dynamic.getReplacementBaseType();
return rep == null ? null : getIsfObject(rep, monitor);
}
else if (dt instanceof BuiltInDataType builtin) {
return new IsfBuiltIn(builtin);
}
else if (dt instanceof TypeDef typedef) {
return getObjectTypeDef(typedef, monitor);
}
else if (dt instanceof Composite composite) {
return new ExtIsfComposite(composite, this, monitor);
}
else if (dt instanceof Enum enumm) {
return new IsfEnum(enumm);
}
else if (dt instanceof FunctionDefinition funcDef) {
return new ExtIsfFunction(funcDef);
}
else {
Msg.warn(this, "Unable to write datatype. Type unrecognized: " + dt.getClass());
}
return null;
}
@Override
public IsfTypedefBase newTypedefBase(TypeDef typeDef) {
return new ExtIsfTypedefBase(typeDef);
}
@Override
public IsfTypedefPointer newTypedefPointer(TypeDef typeDef) {
return new ExtIsfTypedefPointer(typeDef);
}
public IsfObject newTypedefUser(TypeDef typeDef, IsfObject object) {
return new ExtIsfTypedefUser(typeDef, object);
}
@Override
public IsfTypedObject newTypedObject(DataType dt, IsfObject type) {
return new ExtIsfTypedObject(dt, type);
}
@Override
public IsfObject newIsfDynamicComponent(Dynamic dynamic, IsfObject type, int elementCnt) {
return new ExtIsfDynamicComponent(dynamic, type, elementCnt);
}
}

View file

@ -0,0 +1,30 @@
/* ###
* 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 sarif.export.data;
import ghidra.program.model.data.Dynamic;
import ghidra.program.model.data.ISF.IsfDynamicComponent;
import ghidra.program.model.data.ISF.IsfObject;
public class ExtIsfDynamicComponent extends IsfDynamicComponent {
boolean isVariableLength = true;
public ExtIsfDynamicComponent(Dynamic dt, IsfObject type, int elementCnt) {
super(dt, type, elementCnt);
}
}

View file

@ -0,0 +1,71 @@
/* ###
* 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 sarif.export.data;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.ParameterDefinition;
import ghidra.program.model.data.ISF.IsfFunction;
import ghidra.program.model.data.ISF.IsfUtilities;
public class ExtIsfFunction extends IsfFunction {
String comment;
String callingConventionName;
boolean hasVarArgs;
boolean hasNoReturn;
JsonObject retType;
JsonArray params;
public ExtIsfFunction(FunctionDefinition funcDef) {
super(funcDef);
comment = funcDef.getDescription();
callingConventionName = funcDef.getCallingConventionName();
hasVarArgs = funcDef.hasVarArgs();
hasNoReturn = funcDef.hasNoReturn();
retType = new JsonObject();
DataType rt = funcDef.getReturnType();
if (rt != null && rt != DataType.DEFAULT) {
retType.addProperty("name", rt.getName());
retType.addProperty("location", rt.getCategoryPath().getPath());
retType.addProperty("kind", IsfUtilities.getKind(rt));
retType.addProperty("size", rt.getLength());
}
params = new JsonArray();
ParameterDefinition[] vars = funcDef.getArguments();
for (ParameterDefinition var : vars) {
JsonObject param = new JsonObject();
params.add(param);
DataType dt = var.getDataType();
param.addProperty("name", var.getName());
param.addProperty("size", var.getLength());
param.addProperty("ordinal", var.getOrdinal());
param.addProperty("comment", var.getComment());
if (dt != null) {
param.addProperty("name", dt.getName());
param.addProperty("location", dt.getCategoryPath().getPath());
param.addProperty("kind", IsfUtilities.getKind(dt));
}
}
}
}

View file

@ -0,0 +1,58 @@
/* ###
* 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 sarif.export.data;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ISF.IsfBuiltIn;
import ghidra.program.model.data.ISF.IsfDataTypeDefault;
import ghidra.program.model.data.ISF.IsfEnum;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.data.ISF.IsfTypedObject;
public class ExtIsfTypedObject extends IsfTypedObject {
String typeLocation;
public ExtIsfTypedObject(DataType dt, IsfObject typeObj) {
super(dt, typeObj);
if (typeObj instanceof IsfDataTypeDefault) {
typeLocation = ((IsfDataTypeDefault) typeObj).location;
return;
}
if (typeObj instanceof ExtIsfComposite) {
typeLocation = ((ExtIsfComposite) typeObj).location;
}
if (typeObj instanceof IsfEnum) {
typeLocation = ((IsfEnum) typeObj).location;
}
if (typeObj instanceof ExtIsfTypedefBase) {
typeLocation = ((ExtIsfTypedefBase) typeObj).location;
}
// if (typeObj instanceof IsfTypedefIntegral) {
// typeLocation = ((IsfTypedefIntegral) typeObj).location;
// }
if (typeObj instanceof ExtIsfTypedefPointer) {
typeLocation = ((ExtIsfTypedefPointer) typeObj).location;
}
if (typeObj instanceof ExtIsfTypedObject) {
typeLocation = ((ExtIsfTypedObject) typeObj).location;
}
if (typeObj instanceof IsfBuiltIn) {
typeLocation = ((IsfBuiltIn) typeObj).location;
}
}
}

View file

@ -0,0 +1,38 @@
/* ###
* 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 sarif.export.data;
import ghidra.program.model.data.BuiltInDataType;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.ISF.IsfBuiltIn;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.data.ISF.IsfTypedefBase;
public class ExtIsfTypedefBase extends IsfTypedefBase {
public IsfObject type;
public ExtIsfTypedefBase(TypeDef typedef) {
super(typedef);
DataType bdt = typedef.getDataType();
if (bdt instanceof BuiltInDataType) {
type = new IsfBuiltIn((BuiltInDataType) bdt);
kind = "typedef";
}
}
}

View file

@ -0,0 +1,40 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sarif.export.data;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.ISF.IsfTypedefPointer;
public class ExtIsfTypedefPointer extends IsfTypedefPointer {
String typeName;
String typeLocation;
boolean autoNamed;
String displayName;
public ExtIsfTypedefPointer(TypeDef typedef) {
super(typedef);
if (typedef != null) {
DataType base = typedef.getDataType();
typeName = base.getName();
typeLocation = base.getCategoryPath().getPath();
autoNamed = typedef.isAutoNamed();
displayName = typedef.getDisplayName();
}
}
}

View file

@ -0,0 +1,36 @@
/* ###
* 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 sarif.export.data;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.TypeDef;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.data.ISF.IsfTypedefUser;
public class ExtIsfTypedefUser extends IsfTypedefUser {
String typeName;
String typeLocation;
public ExtIsfTypedefUser(TypeDef typedef, IsfObject typeObj) {
super(typedef, typeObj);
DataType baseDataType = typedef.getDataType();
kind = "typedef";
typeName = baseDataType.getName();
typeLocation = baseDataType.getCategoryPath().getPath();
}
}

View file

@ -0,0 +1,63 @@
/* ###
* 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 sarif.export.data;
import ghidra.program.model.data.ISF.IsfBuiltIn;
import ghidra.program.model.data.ISF.IsfComposite;
import ghidra.program.model.data.ISF.IsfDataTypeWriter;
import ghidra.program.model.data.ISF.IsfEnum;
import ghidra.program.model.data.ISF.IsfFunction;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.data.ISF.IsfTypedObject;
import ghidra.program.model.data.ISF.IsfTypedefBase;
import ghidra.program.model.data.ISF.IsfTypedefPointer;
import ghidra.program.model.data.ISF.IsfTypedefUser;
import sarif.export.SarifObject;
import sarif.managers.DataTypesSarifMgr;
public class SarifDataType extends SarifObject {
public SarifDataType(IsfObject obj, IsfDataTypeWriter writer) {
super("DataType", DataTypesSarifMgr.KEY, writer.getTree(obj));
message.addProperty("text", objToMessage(obj));
}
private String objToMessage(IsfObject obj) {
if (obj instanceof IsfComposite) {
return ((IsfComposite) obj).kind.equals("struct") ? "DT.Struct" : "DT.Union";
}
if (obj instanceof IsfEnum) {
return "DT.Enum";
}
if (obj instanceof IsfFunction) {
return "DT.Function";
}
if (obj instanceof IsfTypedefBase ||
//obj instanceof IsfTypedefIntegral ||
obj instanceof IsfTypedefPointer ||
obj instanceof IsfTypedefUser) {
return "DT.Typedef";
}
if (obj instanceof IsfTypedObject) {
return "DT.TypedObject";
}
if (obj instanceof IsfBuiltIn) {
return "DT.Builtin";
}
return "DT.Base";
}
}

View file

@ -0,0 +1,64 @@
/* ###
* 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 sarif.export.data;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class SarifDataTypeWriter extends ExtIsfDataTypeWriter {
private JsonArray types = new JsonArray();
public SarifDataTypeWriter(DataTypeManager dtm, List<DataType> target, Writer baseWriter) throws IOException {
super(dtm, target, baseWriter);
metadata = new JsonObject();
baseTypes = types;
userTypes = types;
enums = types;
functions = types;
symbols = new JsonObject();
}
@Override
protected void addSingletons() {
add(baseTypes, "pointer", getTree(new SarifDataType(newTypedefPointer(null), this)));
add(baseTypes, "undefined", getTree(new SarifDataType(newTypedefPointer(null), this)));
}
@Override
protected JsonObject getObjectForDataType(DataType dt, TaskMonitor monitor)
throws IOException, CancelledException {
IsfObject isf = new SarifDataType(getIsfObject(dt, monitor), this);
JsonObject jobj = (JsonObject) getTree(isf);
resolved.put(dt, isf);
return jobj;
}
public JsonArray getResults() {
return types;
}
}

View file

@ -0,0 +1,31 @@
/* ###
* 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 sarif.export.dd;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.listing.Data;
public class ExtComment implements IsfObject {
int commentType;
String comment;
public ExtComment(Data data, int type) {
commentType = type;
comment = data.getComment(type);
}
}

View file

@ -0,0 +1,75 @@
/* ###
* 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 sarif.export.dd;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.data.ISF.IsfSetting;
import ghidra.program.model.listing.Data;
import sarif.managers.CommentsSarifMgr;
public class ExtCommentSet implements IsfObject {
List<ExtComment> comment;
List<IsfSetting> setting;
Map<Integer, ExtCommentSet> embedded;
public ExtCommentSet(Data data) {
exportComments(data);
int n = data.getNumComponents();
if (n > 0) {
for (int i = 0; i < n; i++) {
Data component = data.getComponent(i);
ExtCommentSet cs = new ExtCommentSet(component);
if (cs.comment != null || cs.setting != null || cs.embedded != null) {
if (embedded == null) {
embedded = new HashMap<>();
}
embedded.put(i, cs);
}
}
}
}
private void exportComments(Data data) {
for (int i = 0; i < CommentsSarifMgr.COMMENT_TYPES.length; i++) {
int type = CommentsSarifMgr.COMMENT_TYPES[i];
String cval = data.getComment(type);
if (cval != null) {
if (comment == null) {
comment = new ArrayList<>();
}
ExtComment isf = new ExtComment(data, type);
comment.add(isf);
}
}
for (String n : data.getNames()) {
Object value = data.getValue(n);
if (value != null) {
if (setting == null) {
setting = new ArrayList<>();
}
IsfSetting isf = new IsfSetting(n, value);
setting.add(isf);
}
}
}
}

View file

@ -0,0 +1,36 @@
/* ###
* 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 sarif.export.dd;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ISF.AbstractIsfObject;
import ghidra.program.model.listing.Data;
public class ExtData extends AbstractIsfObject {
String typeName;
String typeLocation;
ExtCommentSet nested;
public ExtData(Data data) {
super(data.getDataType());
DataType dt = data.getDataType();
typeName = dt.getName();
typeLocation = dt.getCategoryPath().getPath();
nested = new ExtCommentSet(data);
}
}

View file

@ -0,0 +1,55 @@
/* ###
* 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 sarif.export.dd;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.listing.Data;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.DefinedDataSarifMgr;
public class SarifDataWriter extends AbstractExtWriter {
private List<Data> definedData = new ArrayList<>();
public SarifDataWriter(List<Data> target, Writer baseWriter) throws IOException {
super(baseWriter);
this.definedData = target;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genData(monitor);
root.add("definedData", objects);
}
private void genData(TaskMonitor monitor) throws CancelledException, IOException{
monitor.initialize(definedData.size());
for (Data d : definedData) {
ExtData isf = new ExtData(d);
SarifObject sarif = new SarifObject("DefinedData", DefinedDataSarifMgr.KEY, getTree(isf), d.getMinAddress(), d.getMaxAddress());
objects.add(getTree(sarif));
monitor.increment();
}
}
}

View file

@ -0,0 +1,26 @@
/* ###
* 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 sarif.export.ep;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.ISF.IsfObject;
public class ExtEntryPoint implements IsfObject {
public ExtEntryPoint(Address addr) {
}
}

View file

@ -0,0 +1,54 @@
/* ###
* 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 sarif.export.ep;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import ghidra.program.model.address.Address;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.ExtEntryPointSarifMgr;
public class SarifEntryPointWriter extends AbstractExtWriter {
private List<Address> entryPoints;
public SarifEntryPointWriter(List<Address> request, Writer baseWriter) throws IOException {
super(baseWriter);
this.entryPoints = request;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genCode(monitor);
root.add("entryPoints", objects);
}
private void genCode(TaskMonitor monitor) throws CancelledException, IOException{
monitor.initialize(entryPoints.size());
for (Address addr : entryPoints) {
ExtEntryPoint isf = new ExtEntryPoint(addr);
SarifObject sarif = new SarifObject(ExtEntryPointSarifMgr.SUBKEY, ExtEntryPointSarifMgr.KEY, getTree(isf), addr, addr);
objects.add(getTree(sarif));
monitor.increment();
}
}
}

View file

@ -0,0 +1,31 @@
/* ###
* 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 sarif.export.equates;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.symbol.Equate;
public class ExtEquate implements IsfObject {
String name;
long value;
public ExtEquate(Equate equate) {
name = equate.getName();
value = equate.getValue();
}
}

View file

@ -0,0 +1,54 @@
/* ###
* 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 sarif.export.equates;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import ghidra.program.model.symbol.Equate;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.EquatesSarifMgr;
public class SarifEquateWriter extends AbstractExtWriter {
private List<Equate> equates;
public SarifEquateWriter(List<Equate> request, Writer baseWriter) throws IOException {
super(baseWriter);
this.equates = request;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genCode(monitor);
root.add("equates", objects);
}
private void genCode(TaskMonitor monitor) throws CancelledException, IOException{
monitor.initialize(equates.size());
for (Equate equate : equates) {
ExtEquate isf = new ExtEquate(equate);
SarifObject sarif = new SarifObject(EquatesSarifMgr.SUBKEY, EquatesSarifMgr.KEY, getTree(isf), null);
objects.add(getTree(sarif));
monitor.increment();
}
}
}

View file

@ -0,0 +1,33 @@
/* ###
* 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 sarif.export.extlib;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.symbol.SourceType;
public class ExtLibrary implements IsfObject {
public String name;
public String location;
public String sourceType;
public ExtLibrary(String name, String path, SourceType sourceType) {
this.name = name;
location = path;
this.sourceType = sourceType.toString();
}
}

View file

@ -0,0 +1,54 @@
/* ###
* 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 sarif.export.extlib;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.symbol.ExternalLocation;
public class ExtLibraryLocation implements IsfObject {
String name;
String location;
String originalImportedName;
String externalAddress;
String symbol;
boolean isFunction = false;
boolean isClass = false;
String source;
public ExtLibraryLocation(ExternalLocation extLoc) {
name = extLoc.getLabel();
originalImportedName = extLoc.getOriginalImportedName();
location = extLoc.getParentNameSpace().getName(true);
externalAddress = extLoc.getExternalSpaceAddress().toString();
isFunction = extLoc.getFunction() != null;
isClass = extLoc.getClass() != null;
source = extLoc.getSource().toString();
symbol = extLoc.getSymbol().getName();
}
// public ExtLibraryLocation(GhidraClass cls, ExternalLocation extLoc) {
// name = extLoc.getLabel();
// originalImportedName = extLoc.getOriginalImportedName();
// location = extLoc.getParentName();
// //location = cls.getParentNamespace().getName();
// externalAddress = extLoc.getExternalSpaceAddress().toString();
// Function f = extLoc.getFunction();
// isFunction = f != null;
// source = extLoc.getSource().toString();
// symbol = extLoc.getSymbol().getName(true);
// }
}

View file

@ -0,0 +1,96 @@
/* ###
* 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 sarif.export.extlib;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.google.gson.JsonArray;
import ghidra.program.model.listing.GhidraClass;
import ghidra.program.model.symbol.ExternalLocation;
import ghidra.program.model.symbol.ExternalManager;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolIterator;
import ghidra.program.model.symbol.SymbolTable;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.ExternalLibSarifMgr;
public class SarifClassesNamespaceWriter extends AbstractExtWriter {
private List<GhidraClass> classes = new ArrayList<>();
private ExternalManager externalManager;
private SymbolTable symbolTable;
public SarifClassesNamespaceWriter(ExternalManager externalManager, SymbolTable symbolTable, List<GhidraClass> request, Writer baseWriter)
throws IOException {
super(baseWriter);
this.externalManager = externalManager;
this.symbolTable = symbolTable;
this.classes = request;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genClasses(monitor);
root.add("definedData", objects);
}
private void genClasses(TaskMonitor monitor) throws CancelledException, IOException {
monitor.initialize(classes.size());
Iterator<GhidraClass> classNamespaces = symbolTable.getClassNamespaces();
while (classNamespaces.hasNext()) {
GhidraClass next = classNamespaces.next();
walkSymbols(next);
monitor.increment();
}
}
private void walkSymbols(GhidraClass cls) {
String clsName = cls.getName(true);
String path = externalManager.getExternalLibraryPath(clsName);
if (path == null) {
path = "";
}
ExtLibrary lib = new ExtLibrary(clsName, path, SourceType.DEFAULT);
SarifObject sarif = new SarifObject(ExternalLibSarifMgr.SUBKEY0, ExternalLibSarifMgr.KEY, getTree(lib), null);
objects.add(getTree(sarif));
SymbolIterator symbols = symbolTable.getSymbols(cls);
while (symbols.hasNext()) {
Symbol sym = symbols.next();
if (cls.isExternal()) {
ExternalLocation loc = externalManager.getExternalLocation(sym);
ExtLibraryLocation obj = new ExtLibraryLocation(loc);
SarifObject sarif2 = new SarifObject(ExternalLibSarifMgr.SUBKEY1, ExternalLibSarifMgr.KEY, getTree(obj),
loc.getAddress(), loc.getAddress());
objects.add(getTree(sarif2));
}
}
}
public JsonArray getResults() {
return objects;
}
}

View file

@ -0,0 +1,79 @@
/* ###
* 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 sarif.export.extlib;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.JsonArray;
import ghidra.program.model.symbol.ExternalLocation;
import ghidra.program.model.symbol.ExternalLocationIterator;
import ghidra.program.model.symbol.ExternalManager;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.ExternalLibSarifMgr;
public class SarifExternalLibraryWriter extends AbstractExtWriter {
private List<String> externalNames = new ArrayList<>();
private ExternalManager externalManager;
public SarifExternalLibraryWriter(ExternalManager externalManager, List<String> request, Writer baseWriter)
throws IOException {
super(baseWriter);
this.externalManager = externalManager;
this.externalNames = request;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genLibraries(monitor);
root.add("definedData", objects);
}
private void genLibraries(TaskMonitor monitor) throws CancelledException, IOException {
monitor.initialize(externalNames.size());
for (String n : externalNames) {
String path = externalManager.getExternalLibraryPath(n);
if (path == null) {
path = "";
}
ExtLibrary lib = new ExtLibrary(n, path, SourceType.DEFAULT);
SarifObject sarif = new SarifObject(ExternalLibSarifMgr.SUBKEY0, ExternalLibSarifMgr.KEY, getTree(lib), null);
objects.add(getTree(sarif));
ExternalLocationIterator externalLocations = externalManager.getExternalLocations(n);
while (externalLocations.hasNext()) {
ExternalLocation loc = externalLocations.next();
ExtLibraryLocation obj = new ExtLibraryLocation(loc);
SarifObject sarif2 = new SarifObject(ExternalLibSarifMgr.SUBKEY1, ExternalLibSarifMgr.KEY, getTree(obj), loc.getAddress(), loc.getAddress());
objects.add(getTree(sarif2));
}
monitor.increment();
}
}
public JsonArray getResults() {
return objects;
}
}

View file

@ -0,0 +1,33 @@
/* ###
* 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 sarif.export.func;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ISF.AbstractIsfObject;
import ghidra.program.model.data.ISF.IsfUtilities;
public class ExtDataType extends AbstractIsfObject{
String kind;
int size;
public ExtDataType(DataType dt) {
super(dt);
kind = IsfUtilities.getKind(dt);
size = dt.getLength();
}
}

View file

@ -0,0 +1,120 @@
/* ###
* 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 sarif.export.func;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.GlobalNamespace;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.GhidraClass;
import ghidra.program.model.listing.Parameter;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.SourceType;
import ghidra.util.task.TaskMonitor;
public class ExtFunction implements IsfObject {
String name;
String namespace;
boolean namespaceIsClass;
String location;
String comment;
String repeatableComment;
String value;
String callingConvention;
String callFixup;
String signatureSource;
String sourceType;
boolean hasVarArgs;
boolean isInline;
boolean hasNoReturn;
boolean hasCustomStorage;
boolean isStackPurgeSizeValid;
boolean isLibrary;
boolean isGlobal;
boolean isExternal;
boolean isThunk;
String thunkAddress;
ExtFunctionStack stack;
List<ExtFunctionRegVar> regVars = new ArrayList<>();
ExtFunctionParam ret;
List<ExtFunctionParam> params = new ArrayList<>();
public ExtFunction(Function func, TaskMonitor monitor) {
super();
name = func.getName(true);
location = func.getEntryPoint().toString();
comment = func.getComment();
repeatableComment = func.getRepeatableComment();
signatureSource = func.getSignatureSource().toString();
SourceType srcType = func.getSymbol().getSource();
sourceType = srcType.toString();
if (srcType != SourceType.DEFAULT) {
name = func.getName();
}
Namespace ns = func.getParentNamespace();
if (!(ns instanceof GlobalNamespace)) {
namespace = ns.getName(true);
if (ns instanceof GhidraClass) {
namespaceIsClass = true;
}
}
if (func.getSignatureSource() != SourceType.DEFAULT) {
value = func.getPrototypeString(true, true);
}
callingConvention = func.getCallingConventionName();
callFixup = func.getCallFixup();
hasVarArgs = func.hasVarArgs();
isInline = func.isInline();
hasNoReturn = func.hasNoReturn();
hasCustomStorage = func.hasCustomVariableStorage();
isStackPurgeSizeValid = func.isStackPurgeSizeValid();
isLibrary = func.isLibrary();
isGlobal = func.isGlobal();
isExternal = func.isExternal();
isThunk = func.isThunk();
if (func.isThunk()) {
Address thunkAddr = func.getThunkedFunction(false).getEntryPoint();
thunkAddress = thunkAddr.toString();
}
stack = new ExtFunctionStack(func.getStackFrame(), hasCustomStorage);
if (func.isStackPurgeSizeValid()) {
stack.setPurgeSize(func.getStackPurgeSize());
}
Parameter rp = func.getReturn();
ret = new ExtFunctionParam(rp);
Parameter[] fnParams = func.getParameters();
for (Parameter param : fnParams) {
if (param.isRegisterVariable()) {
regVars.add(new ExtFunctionRegVar(param));
}
params.add(new ExtFunctionParam(param));
}
}
}

View file

@ -0,0 +1,81 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sarif.export.func;
import java.util.ArrayList;
import java.util.List;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ISF.AbstractIsfObject;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Parameter;
public class ExtFunctionParam extends AbstractIsfObject {
String comment;
int ordinal;
int size;
String typeName;
String typeLocation;
ExtDataType type;
String formalTypeName;
String formalTypeLocation;
ExtDataType formalType;
boolean isAutoParameter;
boolean isForcedIndirect;
List<String> registers;
int stackOffset;
public ExtFunctionParam(Parameter p) {
super(p.getDataType());
name = p.getName();
ordinal = p.getOrdinal();
size = p.getLength();
comment = p.getComment();
isAutoParameter = p.isAutoParameter();
isForcedIndirect = p.isForcedIndirect();
DataType dataType = p.getDataType();
typeName = dataType.getName();
typeLocation = dataType.getCategoryPath().getPath();
type = new ExtDataType(dataType);
dataType = p.getFormalDataType();
formalTypeName = dataType.getName();
formalTypeLocation = dataType.getCategoryPath().getPath();
formalType = new ExtDataType(dataType);
List<Register> regs = p.getRegisters();
if (regs != null) {
registers = new ArrayList<>();
for (Register r : regs) {
registers.add(r.getName());
}
}
try {
stackOffset = p.getStackOffset();
} catch (UnsupportedOperationException uoe) {
stackOffset = -1;
}
}
}

View file

@ -0,0 +1,45 @@
/* ###
* 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 sarif.export.func;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ISF.AbstractIsfObject;
import ghidra.program.model.listing.Parameter;
public class ExtFunctionRegVar extends AbstractIsfObject {
String register;
String comment;
int size;
String typeName;
String typeLocation;
ExtDataType type;
public ExtFunctionRegVar(Parameter var) {
super(var.getDataType());
name = var.getName();
register = var.getRegister().getName();
size = var.getLength();
comment = var.getComment();
DataType dataType = var.getDataType();
typeName = dataType.getName();
typeLocation = dataType.getCategoryPath().getPath();
type = new ExtDataType(dataType);
}
}

View file

@ -0,0 +1,33 @@
/* ###
* 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 sarif.export.func;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ISF.AbstractIsfObject;
import ghidra.program.model.data.ISF.IsfUtilities;
public class ExtFunctionRet extends AbstractIsfObject {
String kind;
int size;
public ExtFunctionRet(DataType rt) {
super(rt);
kind = IsfUtilities.getKind(rt);
size = rt.getLength();
}
}

View file

@ -0,0 +1,63 @@
/* ###
* 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 sarif.export.func;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.listing.Parameter;
import ghidra.program.model.listing.StackFrame;
import ghidra.program.model.listing.Variable;
public class ExtFunctionStack implements IsfObject {
int localVarSize;
int parameterOffset;
int returnAddressOffset;
int purgeSize;
List<ExtFunctionStackVar> stackVars = new ArrayList<>();
public ExtFunctionStack(StackFrame stackFrame, boolean hasCustomStorage) {
localVarSize = stackFrame.getLocalSize();
parameterOffset = stackFrame.getParameterOffset();
returnAddressOffset = stackFrame.getReturnAddressOffset();
Variable[] vars = stackFrame.getStackVariables();
if (hasCustomStorage) {
Arrays.sort(vars, new Comparator<Variable>() {
@Override
public int compare(Variable o1, Variable o2) {
if (o1 instanceof Parameter p1 && o2 instanceof Parameter p2) {
return p1.getOrdinal() - p2.getOrdinal();
}
return o1.getStackOffset() - o2.getStackOffset();
}
});
}
for (Variable var : vars) {
stackVars.add(new ExtFunctionStackVar(var));
}
}
public void setPurgeSize(int purgeSize) {
this.purgeSize = purgeSize;
}
}

View file

@ -0,0 +1,45 @@
/* ###
* 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 sarif.export.func;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.ISF.AbstractIsfObject;
import ghidra.program.model.listing.Variable;
public class ExtFunctionStackVar extends AbstractIsfObject {
String comment;
int size;
int offset;
String typeName;
String typeLocation;
ExtDataType type;
public ExtFunctionStackVar(Variable var) {
super(var.getDataType());
name = var.getName();
size = var.getLength();
offset = var.getStackOffset();
comment = var.getComment();
DataType dataType = var.getDataType();
typeName = dataType.getName();
typeLocation = dataType.getCategoryPath().getPath();
type = new ExtDataType(dataType);
}
}

View file

@ -0,0 +1,51 @@
/* ###
* 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 sarif.export.func;
import java.io.IOException;
import java.io.Writer;
import com.google.gson.JsonObject;
import ghidra.program.model.data.DataTypeManager;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class ExtFunctionWriter {
protected JsonObject data = new JsonObject();
public ExtFunctionWriter(DataTypeManager dtm, Writer baseWriter) throws IOException {
}
/**
* Exports all root types in the list as ISF JSON.
*
* @param monitor the task monitor
* @return the resultant JSON object
* @throws IOException if there is an exception writing the output
* @throws CancelledException if the action is cancelled by the user
*/
public JsonObject getRootObject(TaskMonitor monitor) throws IOException, CancelledException {
genFunctions(monitor);
return data;
}
private void genFunctions(TaskMonitor monitor) {
// TODO Auto-generated method stub
}
}

View file

@ -0,0 +1,85 @@
/* ###
* 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 sarif.export.func;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import com.google.gson.JsonArray;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.symbol.Namespace;
import ghidra.program.model.symbol.Symbol;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.export.symbols.ExtSymbol;
import sarif.managers.FunctionsSarifMgr;
import sarif.managers.SymbolTableSarifMgr;
public class SarifFunctionWriter extends AbstractExtWriter {
private List<Function> requestedFunctions = new ArrayList<>();
public SarifFunctionWriter(FunctionManager mgr, List<Function> requestedFunctions, Writer baseWriter) throws IOException {
super(baseWriter);
this.requestedFunctions = requestedFunctions;
}
public void requestFunction(Function next) {
requestedFunctions.add(next);
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genFunctions(monitor);
root.add("functions", objects);
}
private void genFunctions(TaskMonitor monitor) throws CancelledException, IOException{
monitor.initialize(requestedFunctions.size());
for (Function f : requestedFunctions) {
addSymbol(f.getSymbol());
ExtFunction isf = new ExtFunction(f, monitor);
SarifObject sarif = new SarifObject("Function", FunctionsSarifMgr.KEY, getTree(isf), f.getBody());
objects.add(getTree(sarif));
monitor.increment();
}
}
private void addSymbol(Symbol s) {
Namespace pspace = s.getParentNamespace();
if (pspace == null) {
return;
}
if (!pspace.isGlobal()) {
Symbol p = s.getParentSymbol();
addSymbol(p);
}
ExtSymbol lib = new ExtSymbol(s);
SarifObject sarif = new SarifObject("Symbol", SymbolTableSarifMgr.KEY, getTree(lib), s.getAddress(), s.getAddress());
objects.add(getTree(sarif));
}
public JsonArray getResults() {
return objects;
}
}

View file

@ -0,0 +1,78 @@
/* ###
* 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 sarif.export.mm;
import java.io.IOException;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.address.OverlayAddressSpace;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.mem.MemoryBlockSourceInfo;
import ghidra.program.model.mem.MemoryBlockType;
import sarif.managers.MemoryMapBytesFile;
public class ExtMemoryMap implements IsfObject {
String name;
String kind;
String overlaySpace;
String overlayedSpace;
String comment;
boolean isVolatile;
String type;
String location;
public ExtMemoryMap(AddressRange range, MemoryBlock block, MemoryMapBytesFile bf, boolean write) throws IOException {
String permissions = "";
if (block.isRead()) {
permissions += "r";
}
if (block.isWrite()) {
permissions += "w";
}
if (block.isExecute()) {
permissions += "x";
}
name = block.getName();
kind = permissions;
AddressSpace space = range.getAddressSpace();
if (space instanceof OverlayAddressSpace) {
OverlayAddressSpace oSpace = (OverlayAddressSpace) space;
overlaySpace = oSpace.getName();
overlayedSpace = oSpace.getOverlayedSpace().getName();
}
if (block.getComment() != null) {
comment = block.getComment();
}
if (block.isVolatile()) {
isVolatile = true;
}
type = block.getType().name();
if (block.getType() == MemoryBlockType.BIT_MAPPED || block.getType() == MemoryBlockType.BYTE_MAPPED) {
// bit mapped blocks can only have one sub-block
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
location = info.getMappedRange().get().getMinAddress().toString();
} else if (block.isInitialized() && write) {
location = bf.getFileName() + ":" + bf.getOffset();
bf.writeBytes(range);
}
}
}

View file

@ -0,0 +1,64 @@
/* ###
* 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 sarif.export.mm;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import generic.stl.Pair;
import ghidra.program.model.address.AddressRange;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.MemoryMapBytesFile;
import sarif.managers.MemoryMapSarifMgr;
public class SarifMemoryMapWriter extends AbstractExtWriter {
private List<Pair<AddressRange, MemoryBlock>> memory;
private MemoryMapBytesFile bytesFile;
private boolean write;
public SarifMemoryMapWriter(List<Pair<AddressRange, MemoryBlock>> request, Writer baseWriter,
MemoryMapBytesFile bytes, boolean isWriteContents) throws IOException {
super(baseWriter);
this.memory = request;
this.bytesFile = bytes;
this.write = isWriteContents;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genMaps(monitor);
root.add("memory", objects);
}
private void genMaps(TaskMonitor monitor) throws CancelledException, IOException {
monitor.initialize(memory.size());
for (Pair<AddressRange, MemoryBlock> m : memory) {
AddressRange range = m.first;
ExtMemoryMap isf = new ExtMemoryMap(m.first, m.second, bytesFile, write);
SarifObject sarif = new SarifObject(MemoryMapSarifMgr.SUBKEY, MemoryMapSarifMgr.KEY, getTree(isf),
range.getMinAddress(), range.getMaxAddress());
objects.add(getTree(sarif));
monitor.increment();
}
}
}

View file

@ -0,0 +1,178 @@
/* ###
* 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 sarif.export.props;
import java.awt.Color;
import java.awt.Font;
import java.io.File;
import java.util.Date;
import javax.swing.KeyStroke;
import ghidra.framework.options.CustomOption;
import ghidra.framework.options.OptionType;
import ghidra.framework.options.Options;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.util.exception.AssertException;
public class ExtProperty implements IsfObject {
String name;
String type;
String value;
public ExtProperty(String name, String type, String value) {
this.name = name;
this.type = type;
this.value = value;
}
public ExtProperty(String name, Options propList) {
this.name = name;
OptionType optionType = propList.getType(name);
switch (optionType) {
case INT_TYPE:
type = "int";
value = Integer.toString(propList.getInt(name, 0));
break;
case LONG_TYPE:
type = "long";
value = Long.toString(propList.getLong(name, 0));
break;
case STRING_TYPE:
type = "string";
value = propList.getString(name, "");
break;
case BOOLEAN_TYPE:
type = "bool";
value = Boolean.toString(propList.getBoolean(name, true));
break;
case DOUBLE_TYPE:
type = "double";
value = Double.toString(propList.getDouble(name, 0));
break;
case FLOAT_TYPE:
type = "float";
value = Float.toString(propList.getFloat(name, 0f));
break;
case DATE_TYPE:
type = "date";
Date date = propList.getDate(name, (Date) null);
long time = date == null ? 0 : date.getTime();
value = Long.toHexString(time);
break;
case COLOR_TYPE:
type = "color";
Color color = propList.getColor(name, null);
int rgb = color.getRGB();
value = Integer.toHexString(rgb);
break;
case ENUM_TYPE:
type = "enum";
@SuppressWarnings({ "unchecked", "rawtypes" })
Enum enuum = propList.getEnum(name, null);
String enumString = OptionType.ENUM_TYPE.convertObjectToString(enuum);
value = escapeElementEntities(enumString);
break;
case FILE_TYPE:
type = "file";
File file = propList.getFile(name, null);
String path = file.getAbsolutePath();
value = path;
break;
case FONT_TYPE:
type = "font";
Font font = propList.getFont(name, null);
enumString = OptionType.FONT_TYPE.convertObjectToString(font);
value = escapeElementEntities(enumString);
break;
case KEYSTROKE_TYPE:
type = "keyStroke";
KeyStroke keyStroke = propList.getKeyStroke(name, null);
enumString = OptionType.KEYSTROKE_TYPE.convertObjectToString(keyStroke);
value = escapeElementEntities(enumString);
break;
case CUSTOM_TYPE:
type = "custom";
CustomOption custom = propList.getCustomOption(name, null);
enumString = OptionType.CUSTOM_TYPE.convertObjectToString(custom);
value = escapeElementEntities(enumString);
break;
case BYTE_ARRAY_TYPE:
type = "bytes";
byte[] bytes = propList.getByteArray(name, null);
enumString = OptionType.BYTE_ARRAY_TYPE.convertObjectToString(bytes);
value = escapeElementEntities(enumString);
break;
case NO_TYPE:
break;
default:
throw new AssertException();
}
}
private static final String LESS_THAN = "&lt;";
private static final String GREATER_THAN = "&gt;";
private static final String APOSTROPHE = "&apos;";
private static final String QUOTE = "&quot;";
private static final String AMPERSAND = "&amp;";
/**
* Converts any special or reserved characters in the specified SARIF string
* into the equivalent Unicode encoding.
*
* @param sarif the SARIF string
* @return the encoded SARIF string
*/
public static String escapeElementEntities(String sarif) {
StringBuilder buffer = new StringBuilder();
for (int offset = 0; offset < sarif.length();) {
int codePoint = sarif.codePointAt(offset);
offset += Character.charCount(codePoint);
if ((codePoint < ' ') && (codePoint != 0x09) && (codePoint != 0x0A) && (codePoint != 0x0D)) {
continue;
}
if (codePoint >= 0x7F) {
buffer.append("&#x");
buffer.append(Integer.toString(codePoint, 16).toUpperCase());
buffer.append(";");
continue;
}
switch (codePoint) {
case '<':
buffer.append(LESS_THAN);
break;
case '>':
buffer.append(GREATER_THAN);
break;
case '\'':
buffer.append(APOSTROPHE);
break;
case '"':
buffer.append(QUOTE);
break;
case '&':
buffer.append(AMPERSAND);
break;
default:
buffer.appendCodePoint(codePoint);
break;
}
}
return buffer.toString();
}
}

View file

@ -0,0 +1,72 @@
/* ###
* 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 sarif.export.props;
import java.io.IOException;
import java.io.Writer;
import java.util.Collections;
import java.util.List;
import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.PropertiesSarifMgr;
public class SarifPropertyListWriter extends AbstractExtWriter {
Program program;
List<String> options;
public SarifPropertyListWriter(Program program, List<String> request, Writer baseWriter) throws IOException {
super(baseWriter);
this.program = program;
this.options = request;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genList(monitor);
root.add("properties", objects);
}
private void genList(TaskMonitor monitor) throws CancelledException, IOException {
monitor.initialize(options.size());
for (String listName : options) {
Options propList = program.getOptions(listName);
List<String> propNames = propList.getOptionNames();
Collections.sort(propNames);
for (String name : propNames) {
if (monitor.isCancelled()) {
throw new CancelledException();
}
if (propList.isAlias(name)) { // don't write out properties that are just mirrors of some other property
continue;
}
if (propList.isDefaultValue(name)) { // don't write out default properties.
continue;
}
String keyName = listName + Options.DELIMITER_STRING + name;
ExtProperty isf = new ExtProperty(keyName, propList);
SarifObject sarif = new SarifObject(PropertiesSarifMgr.SUBKEY, PropertiesSarifMgr.KEY, getTree(isf), null);
objects.add(getTree(sarif));
}
}
}
}

View file

@ -0,0 +1,169 @@
/* ###
* 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 sarif.export.props;
import java.io.IOException;
import java.io.Writer;
import java.util.List;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressIterator;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.Program;
import ghidra.program.model.util.IntPropertyMap;
import ghidra.program.model.util.LongPropertyMap;
import ghidra.program.model.util.ObjectPropertyMap;
import ghidra.program.model.util.PropertyMap;
import ghidra.program.model.util.StringPropertyMap;
import ghidra.program.model.util.VoidPropertyMap;
import ghidra.util.SaveableColor;
import ghidra.util.SaveablePoint;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.NoValueException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
import sarif.managers.PropertiesSarifMgr;
public class SarifPropertyMapWriter extends AbstractExtWriter {
List<PropertyMap<?>> maps;
Program program;
AddressSetView set;
public SarifPropertyMapWriter(List<PropertyMap<?>> request, Program program, AddressSetView set, Writer baseWriter)
throws IOException {
super(baseWriter);
this.maps = request;
this.program = program;
this.set = set;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genMap(monitor);
root.add("properties", objects);
}
private void genMap(TaskMonitor monitor) throws CancelledException, IOException {
monitor.initialize(maps.size());
for (PropertyMap<?> map : maps) {
if (map instanceof VoidPropertyMap) {
genVoidMap((VoidPropertyMap) map, monitor);
} else if (map instanceof IntPropertyMap) {
genIntMap((IntPropertyMap) map, monitor);
} else if (map instanceof LongPropertyMap) {
genLongMap((LongPropertyMap) map, monitor);
} else if (map instanceof StringPropertyMap) {
genStringMap((StringPropertyMap) map, monitor);
} else if (map instanceof ObjectPropertyMap) {
genObjectMap((ObjectPropertyMap<?>) map, monitor);
}
}
}
private void genVoidMap(VoidPropertyMap map, TaskMonitor monitor) throws CancelledException {
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
while (iter.hasNext()) {
Address addr = iter.next();
ExtProperty isf = new ExtProperty(map.getName(), "void", null);
SarifObject sarif = new SarifObject(PropertiesSarifMgr.SUBKEY, PropertiesSarifMgr.KEY, getTree(isf), addr,
addr);
objects.add(getTree(sarif));
monitor.increment();
}
}
private void genIntMap(IntPropertyMap map, TaskMonitor monitor) throws CancelledException {
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
while (iter.hasNext()) {
if (monitor.isCancelled()) {
throw new CancelledException();
}
try {
Address addr = iter.next();
int value = map.getInt(addr);
ExtProperty isf = new ExtProperty(map.getName(), "int", Integer.toHexString(value));
SarifObject sarif = new SarifObject(PropertiesSarifMgr.SUBKEY, PropertiesSarifMgr.KEY, getTree(isf),
addr, addr);
objects.add(getTree(sarif));
} catch (NoValueException e) {
// skip
}
}
}
private void genLongMap(LongPropertyMap map, TaskMonitor monitor) throws CancelledException {
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
while (iter.hasNext()) {
if (monitor.isCancelled()) {
throw new CancelledException();
}
try {
Address addr = iter.next();
long value = map.getLong(addr);
ExtProperty isf = new ExtProperty(map.getName(), "long", Long.toHexString(value));
SarifObject sarif = new SarifObject(PropertiesSarifMgr.SUBKEY, PropertiesSarifMgr.KEY, getTree(isf),
addr, addr);
objects.add(getTree(sarif));
} catch (NoValueException e) {
// skip
}
}
}
private void genStringMap(StringPropertyMap map, TaskMonitor monitor) throws CancelledException {
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
while (iter.hasNext()) {
if (monitor.isCancelled()) {
throw new CancelledException();
}
Address addr = iter.next();
String value = map.getString(addr);
ExtProperty isf = new ExtProperty(map.getName(), "string", value);
SarifObject sarif = new SarifObject(PropertiesSarifMgr.SUBKEY, PropertiesSarifMgr.KEY, getTree(isf), addr,
addr);
objects.add(getTree(sarif));
}
}
private void genObjectMap(ObjectPropertyMap<?> map, TaskMonitor monitor) throws CancelledException {
AddressIterator iter = set != null ? map.getPropertyIterator(set) : map.getPropertyIterator();
while (iter.hasNext()) {
if (monitor.isCancelled()) {
throw new CancelledException();
}
Address addr = iter.next();
Object value = map.get(addr);
ExtProperty isf;
if (value instanceof SaveablePoint) {
isf = new ExtProperty(map.getName(), "point", value.toString());
}
else if (value instanceof SaveableColor) {
isf = new ExtProperty(map.getName(), "color", value.toString());
}
else {
return;
}
SarifObject sarif = new SarifObject(PropertiesSarifMgr.SUBKEY, PropertiesSarifMgr.KEY, getTree(isf), addr,
addr);
objects.add(getTree(sarif));
}
}
}

View file

@ -0,0 +1,32 @@
/* ###
* 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 sarif.export.ref;
import ghidra.program.model.symbol.EquateReference;
public class ExtEquateReference {
String name;
int opIndex;
long value;
public ExtEquateReference(EquateReference ref, String name, long value) {
this.name = name;
this.value = value;
opIndex = ref.getOpIndex();
}
}

View file

@ -0,0 +1,55 @@
/* ###
* 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 sarif.export.ref;
import ghidra.program.model.address.Address;
import ghidra.program.model.symbol.ExternalLocation;
import ghidra.program.model.symbol.ExternalReference;
public class ExtExternalReference extends ExtReference {
String name;
String origImport;
boolean isClass;
boolean isFunction;
String libLabel;
String libAddr;
String libExtAddr;
public ExtExternalReference(ExternalReference ref) {
super(ref);
ExternalLocation extLoc = ref.getExternalLocation();
String label = extLoc.getLabel();
Address addr = extLoc.getAddress();
Address extAddr = extLoc.getExternalSpaceAddress();
name = extLoc.getParentNameSpace().getName(true);
origImport = extLoc.getOriginalImportedName();
isClass = extLoc.getClass() != null;
isFunction = extLoc.getFunction() != null;
if (label != null) {
libLabel = label;
}
if (addr != null) {
libAddr = addr.toString();
}
if (extAddr != null) {
libExtAddr = extAddr.toString();
}
}
}

View file

@ -0,0 +1,39 @@
/* ###
* 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 sarif.export.ref;
import ghidra.program.model.symbol.OffsetReference;
import ghidra.program.model.symbol.Reference;
public class ExtMemoryReference extends ExtReference {
String to;
String base;
long offset;
boolean primary;
public ExtMemoryReference(Reference ref) {
super(ref);
to = ref.getToAddress().toString();
if (ref.isOffsetReference()) {
OffsetReference oref = (OffsetReference) ref;
base = oref.getBaseAddress().toString();
offset = oref.getOffset();
}
primary = ref.isPrimary();
}
}

View file

@ -0,0 +1,35 @@
/* ###
* 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 sarif.export.ref;
import ghidra.program.model.data.ISF.IsfObject;
import ghidra.program.model.symbol.Reference;
public abstract class ExtReference implements IsfObject {
String index;
String kind;
int opIndex;
String sourceType;
public ExtReference(Reference ref) {
index = Byte.toString(ref.getReferenceType().getValue());
kind = ref.getReferenceType().getName();
opIndex = ref.getOperandIndex();
sourceType = ref.getSource().toString();
}
}

View file

@ -0,0 +1,31 @@
/* ###
* 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 sarif.export.ref;
import ghidra.program.model.symbol.Reference;
public class ExtRegisterReference extends ExtReference {
String to;
boolean primary;
public ExtRegisterReference(Reference ref) {
super(ref);
to = ref.getToAddress().toString();
primary = ref.isPrimary();
}
}

View file

@ -0,0 +1,31 @@
/* ###
* 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 sarif.export.ref;
import ghidra.program.model.symbol.ShiftedReference;
public class ExtShiftedReference extends ExtReference {
int shift;
long value;
public ExtShiftedReference(ShiftedReference ref) {
super(ref);
shift = ref.getShift();
value = ref.getValue();
}
}

View file

@ -0,0 +1,29 @@
/* ###
* 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 sarif.export.ref;
import ghidra.program.model.symbol.StackReference;
public class ExtStackReference extends ExtReference {
int offset;
public ExtStackReference(StackReference ref) {
super(ref);
offset = ref.getStackOffset();
}
}

View file

@ -0,0 +1,81 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package sarif.export.ref;
import java.io.IOException;
import java.io.Writer;
import java.util.Iterator;
import com.google.gson.JsonArray;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.symbol.Equate;
import ghidra.program.model.symbol.EquateReference;
import ghidra.program.model.symbol.EquateTable;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
import sarif.export.AbstractExtWriter;
import sarif.export.SarifObject;
public class SarifEquateRefWriter extends AbstractExtWriter {
private AddressSetView set;
private EquateTable equateTable;
public SarifEquateRefWriter(EquateTable equateTable, AddressSetView set, Writer baseWriter) throws IOException {
super(baseWriter);
this.equateTable = equateTable;
this.set = set;
}
@Override
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
genReferences(monitor);
root.add("equates", objects);
}
private void genReferences(TaskMonitor monitor) throws CancelledException, IOException{
Iterator<Equate> iter = equateTable.getEquates();
while (iter.hasNext()) {
if (monitor.isCancelled()) {
throw new CancelledException();
}
Equate equate = iter.next();
String name = equate.getName();
long value = equate.getValue();
EquateReference[] refs = equate.getReferences();
for (int i = 0; i < refs.length; i++) {
if (monitor.isCancelled()) {
return;
}
Address addr = refs[i].getAddress();
if (!set.contains(addr)) {
continue;
}
ExtEquateReference eref = new ExtEquateReference(refs[i], name, value);
SarifObject sarif = new SarifObject("Ref.Equate", "REFERENCES", getTree(eref), addr, addr);
objects.add(getTree(sarif));
}
}
}
public JsonArray getResults() {
return objects;
}
}

Some files were not shown because too many files have changed in this diff Show more