mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +02:00
GP-3832 importer/exporter for SARIF
This commit is contained in:
parent
c225fac124
commit
31ca84453a
174 changed files with 15711 additions and 334 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -188,14 +188,14 @@ public class ExportToIsfAction extends DockingAction {
|
|||
fileChooser.dispose();
|
||||
}
|
||||
|
||||
private class DataTypeWriterTask extends Task {
|
||||
public class DataTypeWriterTask extends Task {
|
||||
|
||||
private final DataTypeManager programDataTypeMgr;
|
||||
private final List<DataType> dataTypeList;
|
||||
private final File file;
|
||||
private final GTree gTree;
|
||||
|
||||
DataTypeWriterTask(GTree gTree, DataTypeManager programDataTypeMgr,
|
||||
public DataTypeWriterTask(GTree gTree, DataTypeManager programDataTypeMgr,
|
||||
List<DataType> dataTypeList, File file) {
|
||||
super("Export Data Types", true, false, true);
|
||||
this.gTree = gTree;
|
||||
|
@ -209,12 +209,9 @@ public class ExportToIsfAction extends DockingAction {
|
|||
try {
|
||||
monitor.setMessage("Export to " + file.getName() + "...");
|
||||
IsfDataTypeWriter dataTypeWriter =
|
||||
new IsfDataTypeWriter(programDataTypeMgr, new FileWriter(file));
|
||||
new IsfDataTypeWriter(programDataTypeMgr, dataTypeList, new FileWriter(file));
|
||||
|
||||
try {
|
||||
for (DataType dataType : dataTypeList) {
|
||||
dataTypeWriter.requestType(dataType);
|
||||
}
|
||||
JsonObject object = dataTypeWriter.getRootObject(monitor);
|
||||
dataTypeWriter.write(object);
|
||||
}
|
||||
|
|
|
@ -130,7 +130,7 @@ public class IsfClientHandler {
|
|||
private String lookType(String ns, String key) throws IOException {
|
||||
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
|
||||
isfWriter.setSkipSymbols(true);
|
||||
isfWriter.requestType(key);
|
||||
//isfWriter.requestType(key);
|
||||
return writeFrom(isfWriter);
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ public class IsfClientHandler {
|
|||
|
||||
private IsfDataTypeWriter createDataTypeWriter(DataTypeManager dtm) throws IOException {
|
||||
StringWriter out = new StringWriter();
|
||||
return new IsfDataTypeWriter(dtm, out);
|
||||
return new IsfDataTypeWriter(dtm, null, out);
|
||||
}
|
||||
|
||||
private String writeFrom(IsfDataTypeWriter dataTypeWriter) throws IOException {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -17,16 +17,15 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
import ghidra.program.model.data.BuiltInDataType;
|
||||
|
||||
public class IsfBuiltIn implements IsfObject {
|
||||
public class IsfBuiltIn extends AbstractIsfObject {
|
||||
|
||||
public Integer size;
|
||||
public Boolean signed;
|
||||
public String kind;
|
||||
public String endian;
|
||||
|
||||
public IsfBuiltIn(BuiltInDataType builtin) {
|
||||
super(builtin);
|
||||
size = IsfUtilities.getLength(builtin);
|
||||
signed = IsfUtilities.getSigned(builtin);
|
||||
kind = IsfUtilities.getBuiltInKind(builtin);
|
||||
endian = IsfUtilities.getEndianness(builtin);
|
||||
}
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
package ghidra.program.model.data.ISF;
|
||||
|
||||
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 IsfObject type;
|
||||
|
@ -30,16 +30,25 @@ public class IsfComponent implements IsfObject {
|
|||
@Exclude
|
||||
public String field_name;
|
||||
@Exclude
|
||||
public Boolean noFieldName;
|
||||
@Exclude
|
||||
public String comment;
|
||||
|
||||
|
||||
public IsfComponent(DataTypeComponent component, IsfObject typeObj) {
|
||||
super(component.getDataType());
|
||||
offset = component.getOffset();
|
||||
type = typeObj;
|
||||
|
||||
field_name = component.getFieldName();
|
||||
if (field_name == null || field_name.equals("")) {
|
||||
noFieldName = true;
|
||||
}
|
||||
ordinal = component.getOrdinal();
|
||||
length = component.getLength();
|
||||
comment = component.getComment();
|
||||
|
||||
processSettings(component.getDataType(), component.getDefaultSettings());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,52 +15,50 @@
|
|||
*/
|
||||
package ghidra.program.model.data.ISF;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude;
|
||||
import ghidra.program.model.data.Composite;
|
||||
import ghidra.program.model.data.DataTypeComponent;
|
||||
import ghidra.program.model.data.Structure;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class IsfComposite implements IsfObject {
|
||||
public class IsfComposite extends AbstractIsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer size;
|
||||
public JsonObject fields;
|
||||
|
||||
@Exclude
|
||||
public int alignment;
|
||||
|
||||
|
||||
public IsfComposite(Composite composite, IsfDataTypeWriter writer, TaskMonitor monitor) {
|
||||
super(composite);
|
||||
size = composite.getLength();
|
||||
kind = composite instanceof Structure ? "struct" : "union";
|
||||
alignment = composite.getAlignment();
|
||||
|
||||
DataTypeComponent[] components = composite.getComponents();
|
||||
Map<String, DataTypeComponent> comps = new HashMap<>();
|
||||
for (DataTypeComponent component : components) {
|
||||
String key = component.getFieldName();
|
||||
if (key == null) {
|
||||
key = component.getDefaultFieldName();
|
||||
}
|
||||
comps.put(key, component);
|
||||
if (components.length == 0) {
|
||||
// NB: composite.getLength always returns > 0
|
||||
size = 0;
|
||||
}
|
||||
ArrayList<String> keylist = new ArrayList<>(comps.keySet());
|
||||
Collections.sort(keylist);
|
||||
|
||||
fields = new JsonObject();
|
||||
for (String key : keylist) {
|
||||
for (DataTypeComponent component : components) {
|
||||
if (monitor.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
|
||||
DataTypeComponent component = comps.get(key);
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
protected IsfComponent getComponent(DataTypeComponent component, IsfObject type) {
|
||||
return new IsfComponent(component, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,13 +17,14 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
import ghidra.program.model.data.Array;
|
||||
|
||||
public class IsfDataTypeArray implements IsfObject {
|
||||
public class IsfDataTypeArray extends AbstractIsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer count;
|
||||
public IsfObject subtype;
|
||||
|
||||
public IsfDataTypeArray(Array arr, IsfObject typeObj) {
|
||||
super(arr);
|
||||
kind = IsfUtilities.getKind(arr);
|
||||
count = arr.getNumElements();
|
||||
subtype = typeObj;
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
package ghidra.program.model.data.ISF;
|
||||
|
||||
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 Integer bit_length;
|
||||
|
@ -31,6 +31,7 @@ public class IsfDataTypeBitField implements IsfObject {
|
|||
private int storage_size;
|
||||
|
||||
public IsfDataTypeBitField(BitFieldDataType bf, int componentOffset, IsfObject typeObj) {
|
||||
super(bf);
|
||||
kind = IsfUtilities.getKind(bf);
|
||||
bit_length = bf.getBitSize();
|
||||
bit_offset = bf.getBitOffset();
|
||||
|
|
|
@ -17,14 +17,15 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
public class IsfDataTypeDefault implements IsfObject {
|
||||
public class IsfDataTypeDefault extends AbstractIsfObject {
|
||||
|
||||
public String kind;
|
||||
public String name;
|
||||
int size;
|
||||
|
||||
public IsfDataTypeDefault(DataType dt) {
|
||||
super(dt);
|
||||
kind = IsfUtilities.getKind(dt);
|
||||
name = dt.getName();
|
||||
size = dt.getLength();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,12 +17,13 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
public class IsfDataTypeTypeDef implements IsfObject {
|
||||
public class IsfDataTypeTypeDef extends AbstractIsfObject {
|
||||
|
||||
public String kind;
|
||||
public IsfObject subtype;
|
||||
|
||||
public IsfDataTypeTypeDef(DataType dt, IsfObject typeObj) {
|
||||
super(dt);
|
||||
kind = IsfUtilities.getKind(dt);
|
||||
subtype = typeObj;
|
||||
}
|
||||
|
|
|
@ -17,20 +17,43 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.lang.annotation.*;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
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 ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.model.address.Address;
|
||||
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.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.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.exception.CancelledException;
|
||||
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.
|
||||
*/
|
||||
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 List<String> deferredKeys = new ArrayList<>();
|
||||
public List<String> deferredKeys = new ArrayList<>();
|
||||
|
||||
private Writer baseWriter;
|
||||
private JsonWriter writer;
|
||||
private Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
|
||||
private DataTypeManager dtm;
|
||||
protected DataTypeManager dtm;
|
||||
private DataOrganization dataOrganization;
|
||||
|
||||
private JsonObject data = new JsonObject();
|
||||
private JsonObject metadata = new JsonObject();
|
||||
private JsonObject baseTypes = new JsonObject();
|
||||
private JsonObject userTypes = new JsonObject();
|
||||
private JsonObject enums = new JsonObject();
|
||||
private JsonObject symbols = new JsonObject();
|
||||
protected JsonObject data = new JsonObject();
|
||||
protected JsonElement metadata;
|
||||
protected JsonElement baseTypes;
|
||||
protected JsonElement userTypes;
|
||||
protected JsonElement enums;
|
||||
protected JsonElement functions;
|
||||
protected JsonElement symbols;
|
||||
|
||||
private List<Address> requestedAddresses = 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 boolean skipSymbols = false;
|
||||
private boolean skipTypes = false;
|
||||
|
@ -70,11 +92,13 @@ public class IsfDataTypeWriter {
|
|||
/**
|
||||
* 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
|
||||
* @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;
|
||||
if (dtm != null) {
|
||||
dataOrganization = dtm.getDataOrganization();
|
||||
|
@ -82,66 +106,43 @@ public class IsfDataTypeWriter {
|
|||
if (dataOrganization == null) {
|
||||
dataOrganization = DataOrganizationImpl.getDefaultOrganization();
|
||||
}
|
||||
this.baseWriter = baseWriter;
|
||||
this.writer = new JsonWriter(baseWriter);
|
||||
writer.setIndent(" ");
|
||||
this.gson = new GsonBuilder()
|
||||
.addSerializationExclusionStrategy(strategy)
|
||||
.setPrettyPrinting()
|
||||
.create();
|
||||
|
||||
metadata = new JsonObject();
|
||||
baseTypes = new JsonObject();
|
||||
userTypes = new JsonObject();
|
||||
enums = new JsonObject();
|
||||
functions = new JsonObject();
|
||||
symbols = new JsonObject();
|
||||
requestedDataTypes = target;
|
||||
STRICT = true;
|
||||
}
|
||||
|
||||
@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
|
||||
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 {
|
||||
|
||||
@Override
|
||||
protected void genRoot(TaskMonitor monitor) throws CancelledException, IOException {
|
||||
genMetadata();
|
||||
genTypes(monitor);
|
||||
genSymbols();
|
||||
genRoot();
|
||||
genSymbols(monitor);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
private void genRoot() {
|
||||
data.add("metadata", metadata);
|
||||
data.add("base_types", baseTypes);
|
||||
data.add("user_types", userTypes);
|
||||
data.add("enums", enums);
|
||||
// Would be nice to support this in the futere, but Volatility does not
|
||||
//data.add("typedefs", typedefs);
|
||||
// Would be nice to support this in the future, but Volatility does not
|
||||
// data.add("functions", functions);
|
||||
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() {
|
||||
String oskey = "UNKNOWN";
|
||||
if (dtm instanceof ProgramDataTypeManager) {
|
||||
|
@ -154,20 +155,21 @@ public class IsfDataTypeWriter {
|
|||
oskey = metaData.get("Compiler ID");
|
||||
if (metaData.containsKey("PDB Loaded")) {
|
||||
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")) {
|
||||
oskey = "linux";
|
||||
os = gson.toJsonTree(new IsfLinuxOS(gson, metaData));
|
||||
}
|
||||
}
|
||||
metadata.addProperty("format", "6.2.0");
|
||||
metadata.add("producer", producer);
|
||||
metadata.add(oskey, os);
|
||||
if (metadata instanceof JsonObject) {
|
||||
((JsonObject) metadata).addProperty("format", "6.2.0");
|
||||
}
|
||||
add(metadata, "producer", producer);
|
||||
add(metadata, oskey, os);
|
||||
}
|
||||
}
|
||||
|
||||
private void genSymbols() {
|
||||
private void genSymbols(TaskMonitor monitor) {
|
||||
if (!skipSymbols && dtm instanceof ProgramDataTypeManager) {
|
||||
ProgramDataTypeManager pgmDtm = (ProgramDataTypeManager) dtm;
|
||||
Program program = pgmDtm.getProgram();
|
||||
|
@ -194,18 +196,15 @@ public class IsfDataTypeWriter {
|
|||
Symbol symbol = iterator.next();
|
||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (Address addr : requestedAddresses) {
|
||||
Symbol[] symsFromAddr =
|
||||
symbolTable.getSymbols(addr.add(imageBase.getOffset()));
|
||||
Symbol[] symsFromAddr = symbolTable.getSymbols(addr.add(imageBase.getOffset()));
|
||||
for (Symbol symbol : symsFromAddr) {
|
||||
symbolToJson(imageBase, symbolTable, linkages, map, symbol);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
for (String key : requestedSymbols) {
|
||||
SymbolIterator iter = symbolTable.getSymbols(key);
|
||||
while (iter.hasNext()) {
|
||||
|
@ -215,33 +214,29 @@ public class IsfDataTypeWriter {
|
|||
}
|
||||
}
|
||||
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()) {
|
||||
if (entry.getKey().startsWith("_")) {
|
||||
String nu = entry.getKey().substring(1);
|
||||
if (symbols.get(nu) == null) {
|
||||
symbols.add(nu, entry.getValue());
|
||||
}
|
||||
add(symbols, nu, entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void genTypes(TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
private void genTypes(TaskMonitor monitor) throws CancelledException, IOException {
|
||||
if (skipTypes) {
|
||||
return;
|
||||
}
|
||||
Map<String, DataType> map = new HashMap<>();
|
||||
if (requestedDataTypes.isEmpty()) {
|
||||
dtm.getAllDataTypes(requestedDataTypes);
|
||||
baseTypes.add("pointer", getTree(new IsfTypedefPointer()));
|
||||
baseTypes.add("undefined", getTree(new IsfTypedefPointer()));
|
||||
addSingletons();
|
||||
}
|
||||
monitor.initialize(requestedDataTypes.size());
|
||||
for (DataType dataType : requestedDataTypes) {
|
||||
String key = dataType.getName();
|
||||
String key = dataType.getPathName();
|
||||
map.put(key, dataType);
|
||||
}
|
||||
|
||||
|
@ -260,10 +255,9 @@ public class IsfDataTypeWriter {
|
|||
private void processMap(Map<String, DataType> map, List<String> keylist, TaskMonitor monitor)
|
||||
throws CancelledException, IOException {
|
||||
JsonObject obj = new JsonObject();
|
||||
int cnt = 0;
|
||||
monitor.setMaximum(keylist.size());
|
||||
for (String key : keylist) {
|
||||
DataType dataType = map.get(key);
|
||||
monitor.checkCancelled();
|
||||
if (key.contains(".conflict")) {
|
||||
continue;
|
||||
}
|
||||
|
@ -272,36 +266,29 @@ public class IsfDataTypeWriter {
|
|||
continue;
|
||||
}
|
||||
if (dataType instanceof FunctionDefinition) {
|
||||
// Would be nice to support this in the futere, but Volatility does not
|
||||
//typedefs.add(dataType.getName(), obj);
|
||||
}
|
||||
else if (IsfUtilities.isBaseDataType(dataType)) {
|
||||
baseTypes.add(dataType.getName(), obj);
|
||||
}
|
||||
else if (dataType instanceof TypeDef) {
|
||||
// Would be nice to support this in the future, but Volatility does not
|
||||
add(functions, dataType.getPathName(), obj);
|
||||
} else if (IsfUtilities.isBaseDataType(dataType)) {
|
||||
add(baseTypes, dataType.getPathName(), obj);
|
||||
} else if (dataType instanceof TypeDef) {
|
||||
DataType baseDataType = ((TypeDef) dataType).getBaseDataType();
|
||||
if (IsfUtilities.isBaseDataType(baseDataType)) {
|
||||
baseTypes.add(dataType.getName(), obj);
|
||||
}
|
||||
else if (baseDataType instanceof Enum) {
|
||||
enums.add(dataType.getName(), obj);
|
||||
}
|
||||
else {
|
||||
userTypes.add(dataType.getName(), obj);
|
||||
add(baseTypes, dataType.getPathName(), obj);
|
||||
} else if (baseDataType instanceof Enum) {
|
||||
add(enums, dataType.getPathName(), obj);
|
||||
} else {
|
||||
add(userTypes, dataType.getPathName(), 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) {
|
||||
enums.add(dataType.getName(), obj);
|
||||
}
|
||||
else if (dataType instanceof Composite) {
|
||||
userTypes.add(dataType.getName(), obj);
|
||||
}
|
||||
monitor.setProgress(++cnt);
|
||||
monitor.increment();
|
||||
}
|
||||
}
|
||||
|
||||
private void symbolToJson(Address imageBase, SymbolTable symbolTable,
|
||||
Map<String, Symbol> linkages,
|
||||
private void symbolToJson(Address imageBase, SymbolTable symbolTable, Map<String, Symbol> linkages,
|
||||
Map<String, JsonObject> map, Symbol symbol) {
|
||||
String key = symbol.getName();
|
||||
Address address = symbol.getAddress();
|
||||
|
@ -313,9 +300,12 @@ public class IsfDataTypeWriter {
|
|||
sym.addProperty("linkage_name", linkage.getName());
|
||||
sym.addProperty("address", linkage.getAddress().getOffset());
|
||||
}
|
||||
}
|
||||
else {
|
||||
sym.addProperty("address", address.subtract(imageBase));
|
||||
} else {
|
||||
if (address.getAddressSpace().equals(imageBase.getAddressSpace())) {
|
||||
sym.addProperty("address", address.subtract(imageBase));
|
||||
} else {
|
||||
sym.addProperty("address", address.getOffset());
|
||||
}
|
||||
}
|
||||
map.put(symbol.getName(), sym);
|
||||
if (!symbol.isPrimary()) {
|
||||
|
@ -332,8 +322,12 @@ public class IsfDataTypeWriter {
|
|||
gson.toJson(obj, writer);
|
||||
}
|
||||
|
||||
JsonObject getObjectForDataType(DataType dt, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
protected void addSingletons() {
|
||||
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);
|
||||
if (isf != null) {
|
||||
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
|
||||
* bit-fields and function defs as unsupported by ISF. Typedefs really deserve their own
|
||||
* category, but again unsupported.
|
||||
* Writes the data 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 data type to write as ISF JSON
|
||||
* @param dt the data type to write as ISF JSON
|
||||
* @param monitor the task monitor
|
||||
* @throws IOException if there is an exception writing the output
|
||||
*/
|
||||
private IsfObject getIsfObject(DataType dt, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
protected IsfObject getIsfObject(DataType dt, TaskMonitor monitor) throws IOException, CancelledException {
|
||||
if (dt == null) {
|
||||
Msg.error(this, "Shouldn't get here - null datatype passed");
|
||||
return null;
|
||||
throw new IOException("Null datatype passed to getIsfObject");
|
||||
}
|
||||
if (dt instanceof FactoryDataType) {
|
||||
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 obj = new IsfTypedObject(dt, type);
|
||||
IsfObject obj = newTypedObject(dt, type);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
@ -377,41 +372,33 @@ public class IsfDataTypeWriter {
|
|||
if (dt instanceof Dynamic dynamic) {
|
||||
DataType rep = dynamic.getReplacementBaseType();
|
||||
return rep == null ? null : getIsfObject(rep, monitor);
|
||||
}
|
||||
else if (dt instanceof TypeDef typedef) {
|
||||
} else if (dt instanceof TypeDef typedef) {
|
||||
return getObjectTypeDef(typedef, monitor);
|
||||
}
|
||||
else if (dt instanceof Composite composite) {
|
||||
} else if (dt instanceof Composite composite) {
|
||||
return new IsfComposite(composite, this, monitor);
|
||||
}
|
||||
else if (dt instanceof Enum enumm) {
|
||||
} else if (dt instanceof Enum enumm) {
|
||||
return new IsfEnum(enumm);
|
||||
}
|
||||
else if (dt instanceof BuiltInDataType builtin) {
|
||||
} else if (dt instanceof BuiltInDataType builtin) {
|
||||
return new IsfBuiltIn(builtin);
|
||||
}
|
||||
else if (dt instanceof BitFieldDataType) {
|
||||
} else if (dt instanceof BitFieldDataType) {
|
||||
// skip - not hit
|
||||
}
|
||||
else if (dt instanceof FunctionDefinition) { ///FAIL
|
||||
} else if (dt instanceof FunctionDefinition) { /// FAIL
|
||||
// skip - not hit
|
||||
}
|
||||
else if (dt.equals(DataType.DEFAULT)) {
|
||||
} else if (dt.equals(DataType.DEFAULT)) {
|
||||
// skip - not hit
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Msg.warn(this, "Unable to write datatype. Type unrecognized: " + dt.getClass());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private IsfObject resolve(DataType dt) {
|
||||
public IsfObject resolve(DataType dt) {
|
||||
if (resolved.containsKey(dt)) {
|
||||
return resolved.get(dt);
|
||||
}
|
||||
|
||||
DataType resolvedType = resolvedTypeMap.get(dt.getName());
|
||||
DataType resolvedType = resolvedTypeMap.get(dt.getPathName());
|
||||
if (resolvedType != null) {
|
||||
if (resolvedType.isEquivalent(dt)) {
|
||||
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() +
|
||||
" - " + resolvedType.getPathName());
|
||||
Msg.warn(this,
|
||||
"WARNING! conflicting data type names: " + dt.getPathName() + " - " + resolvedType.getPathName());
|
||||
return resolved.get(dt);
|
||||
}
|
||||
|
||||
resolvedTypeMap.put(dt.getName(), dt);
|
||||
resolvedTypeMap.put(dt.getPathName(), dt);
|
||||
return null;
|
||||
}
|
||||
|
||||
private void clearResolve(String typedefName, DataType baseType) {
|
||||
if (baseType instanceof Composite || baseType instanceof Enum) {
|
||||
// auto-typedef generated with composite and enum
|
||||
if (typedefName.equals(baseType.getName())) {
|
||||
if (typedefName.equals(baseType.getPathName())) {
|
||||
resolvedTypeMap.remove(typedefName);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Inherited from DataTypeWriter (logic lost to time):
|
||||
// A comment explaining the special 'P' case would be helpful!! Smells like fish.
|
||||
// Inherited from DataTypeWriter (logic lost to time):
|
||||
// A comment explaining the special 'P' case would be helpful!! Smells like
|
||||
// fish.
|
||||
else if (baseType instanceof Pointer && typedefName.startsWith("P")) {
|
||||
DataType dt = ((Pointer) baseType).getDataType();
|
||||
if (dt instanceof TypeDef) {
|
||||
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
|
||||
resolvedTypeMap.remove(typedefName);
|
||||
return;
|
||||
|
@ -469,13 +457,11 @@ public class IsfDataTypeWriter {
|
|||
int elementLen = replacementBaseType.getLength();
|
||||
if (elementLen > 0) {
|
||||
int elementCnt = (component.getLength() + elementLen - 1) / elementLen;
|
||||
return new IsfDynamicComponent(dynamic, type, elementCnt);
|
||||
return newIsfDynamicComponent(dynamic, type, elementCnt);
|
||||
|
||||
}
|
||||
Msg.error(this,
|
||||
dynamic.getClass().getSimpleName() +
|
||||
" returned bad replacementBaseType: " +
|
||||
replacementBaseType.getClass().getSimpleName());
|
||||
Msg.error(this, dynamic.getClass().getSimpleName() + " returned bad replacementBaseType: "
|
||||
+ replacementBaseType.getClass().getSimpleName());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -492,7 +478,7 @@ public class IsfDataTypeWriter {
|
|||
return getObjectDataType(dataType, -1);
|
||||
}
|
||||
|
||||
private IsfObject getObjectDataType(DataType dataType, int componentOffset) {
|
||||
public IsfObject getObjectDataType(DataType dataType, int componentOffset) {
|
||||
if (dataType == null) {
|
||||
return new IsfDataTypeNull();
|
||||
}
|
||||
|
@ -509,9 +495,9 @@ public class IsfDataTypeWriter {
|
|||
IsfObject baseObject = getObjectDataType(IsfUtilities.getBaseDataType(dataType));
|
||||
return new IsfDataTypeTypeDef(dataType, baseObject);
|
||||
}
|
||||
if (dataType.getName().contains(".conflict")) {
|
||||
if (!deferredKeys.contains(dataType.getName())) {
|
||||
deferredKeys.add(dataType.getName());
|
||||
if (dataType.getPathName().contains(".conflict")) {
|
||||
if (!deferredKeys.contains(dataType.getPathName())) {
|
||||
deferredKeys.add(dataType.getPathName());
|
||||
}
|
||||
}
|
||||
return new IsfDataTypeDefault(dataType);
|
||||
|
@ -522,27 +508,21 @@ public class IsfDataTypeWriter {
|
|||
*
|
||||
* @throws CancelledException if the action is cancelled by the user
|
||||
*/
|
||||
private IsfObject getObjectTypeDef(TypeDef typeDef, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
//UNVERIFIED
|
||||
protected IsfObject getObjectTypeDef(TypeDef typeDef, TaskMonitor monitor) throws CancelledException {
|
||||
DataType dataType = typeDef.getDataType();
|
||||
String typedefName = typeDef.getDisplayName();
|
||||
String dataTypeName = dataType.getDisplayName();
|
||||
if (IsfUtilities.isIntegral(typedefName, dataTypeName)) {
|
||||
return new IsfTypedefIntegral(typeDef);
|
||||
}
|
||||
String typedefName = typeDef.getPathName();
|
||||
|
||||
DataType baseType = typeDef.getBaseDataType();
|
||||
DataType baseType = typeDef.getDataType();
|
||||
try {
|
||||
if (baseType instanceof BuiltInDataType builtin) {
|
||||
return new IsfTypedefBase(typeDef);
|
||||
return newTypedefBase(typeDef);
|
||||
}
|
||||
if (!(baseType instanceof Pointer)) {
|
||||
return getIsfObject(dataType, monitor);
|
||||
IsfObject isfObject = getIsfObject(dataType, monitor);
|
||||
return newTypedefUser(typeDef, isfObject);
|
||||
}
|
||||
return new IsfTypedefPointer();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return newTypedefPointer(typeDef);
|
||||
} catch (Exception e) {
|
||||
Msg.error(this, "TypeDef error: " + e);
|
||||
}
|
||||
clearResolve(typedefName, baseType);
|
||||
|
@ -550,11 +530,7 @@ public class IsfDataTypeWriter {
|
|||
return null;
|
||||
}
|
||||
|
||||
public JsonElement getTree(Object obj) {
|
||||
return gson.toJsonTree(obj);
|
||||
}
|
||||
|
||||
public void requestAddress(String key) {
|
||||
public void requestAddress(String key) throws IOException {
|
||||
if (dtm instanceof ProgramDataTypeManager pgmDtm) {
|
||||
try {
|
||||
Address address = pgmDtm.getProgram().getMinAddress().getAddress(key);
|
||||
|
@ -563,9 +539,8 @@ public class IsfDataTypeWriter {
|
|||
return;
|
||||
}
|
||||
requestedAddresses.add(address);
|
||||
}
|
||||
catch (AddressFormatException e) {
|
||||
e.printStackTrace();
|
||||
} catch (AddressFormatException e) {
|
||||
throw new IOException("Bad address format: " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -578,24 +553,6 @@ public class IsfDataTypeWriter {
|
|||
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() {
|
||||
return writer;
|
||||
}
|
||||
|
@ -605,16 +562,6 @@ public class IsfDataTypeWriter {
|
|||
return baseWriter.toString();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
try {
|
||||
writer.flush();
|
||||
writer.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void setSkipSymbols(boolean val) {
|
||||
skipSymbols = val;
|
||||
}
|
||||
|
@ -623,7 +570,28 @@ public class IsfDataTypeWriter {
|
|||
skipTypes = val;
|
||||
}
|
||||
|
||||
public void setStrict(boolean val) {
|
||||
STRICT = val;
|
||||
public IsfTypedefBase newTypedefBase(TypeDef typeDef) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,13 +17,14 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
import ghidra.program.model.data.Dynamic;
|
||||
|
||||
public class IsfDynamicComponent implements IsfObject {
|
||||
public class IsfDynamicComponent extends AbstractIsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer count;
|
||||
public IsfObject subtype;
|
||||
|
||||
public IsfDynamicComponent(Dynamic dynamicType, IsfObject type, int elementCnt) {
|
||||
super(dynamicType);
|
||||
kind = "array";
|
||||
subtype = type;
|
||||
count = elementCnt;
|
||||
|
|
|
@ -19,13 +19,14 @@ import com.google.gson.JsonObject;
|
|||
|
||||
import ghidra.program.model.data.Enum;
|
||||
|
||||
public class IsfEnum implements IsfObject {
|
||||
public class IsfEnum extends AbstractIsfObject {
|
||||
|
||||
public Integer size;
|
||||
public String base;
|
||||
public JsonObject constants = new JsonObject();
|
||||
|
||||
public IsfEnum(Enum enumm) {
|
||||
super(enumm);
|
||||
size = enumm.getLength();
|
||||
base = "int";
|
||||
String[] names = enumm.getNames();
|
||||
|
|
|
@ -15,11 +15,14 @@
|
|||
*/
|
||||
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 IsfFunction() {
|
||||
public IsfFunction(FunctionDefinition def) {
|
||||
super(def);
|
||||
kind = "function";
|
||||
}
|
||||
|
||||
|
|
|
@ -18,14 +18,15 @@ package ghidra.program.model.data.ISF;
|
|||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.FunctionDefinition;
|
||||
|
||||
public class IsfFunctionPointer implements IsfObject {
|
||||
public class IsfFunctionPointer extends AbstractIsfObject {
|
||||
|
||||
public String kind;
|
||||
public IsfObject subtype;
|
||||
|
||||
public IsfFunctionPointer(FunctionDefinition def, DataType dt) {
|
||||
super(def);
|
||||
kind = "pointer";
|
||||
subtype = new IsfFunction();
|
||||
subtype = new IsfFunction(def);
|
||||
//TODO?
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,6 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
public interface IsfObject {
|
||||
|
||||
// EMPTY by design
|
||||
|
||||
// EMPTY
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -17,15 +17,16 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
import ghidra.program.model.data.DataType;
|
||||
|
||||
public class IsfTypedObject implements IsfObject {
|
||||
public class IsfTypedObject extends AbstractIsfObject {
|
||||
|
||||
public String kind;
|
||||
public Integer size;
|
||||
public IsfObject type;
|
||||
|
||||
public IsfTypedObject(DataType dt, IsfObject typeObj) {
|
||||
super(dt);
|
||||
kind = IsfUtilities.getKind(dt);
|
||||
size = dt.getLength();
|
||||
size = dt.hasLanguageDependantLength() ? -1 : dt.getLength();
|
||||
type = typeObj;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,18 +18,17 @@ package ghidra.program.model.data.ISF;
|
|||
import ghidra.program.model.data.BuiltInDataType;
|
||||
import ghidra.program.model.data.TypeDef;
|
||||
|
||||
public class IsfTypedefBase implements IsfObject {
|
||||
public class IsfTypedefBase extends AbstractIsfObject {
|
||||
|
||||
public Integer size;
|
||||
public String kind;
|
||||
public Boolean signed;
|
||||
public String endian;
|
||||
|
||||
public IsfTypedefBase(TypeDef typeDef) {
|
||||
super(typeDef);
|
||||
BuiltInDataType builtin = (BuiltInDataType) typeDef.getBaseDataType();
|
||||
size = typeDef.getLength();
|
||||
kind = IsfUtilities.getBuiltInKind(builtin);
|
||||
signed = IsfUtilities.getSigned(typeDef);
|
||||
endian = IsfUtilities.getEndianness(typeDef);
|
||||
}
|
||||
|
||||
|
|
|
@ -17,11 +17,12 @@ package ghidra.program.model.data.ISF;
|
|||
|
||||
import ghidra.program.model.data.TypeDef;
|
||||
|
||||
public class IsfTypedefIntegral implements IsfObject {
|
||||
public class IsfTypedefIntegral extends AbstractIsfObject {
|
||||
|
||||
public Integer size;
|
||||
|
||||
public IsfTypedefIntegral(TypeDef td) {
|
||||
super(td);
|
||||
size = td.getLength();
|
||||
}
|
||||
|
||||
|
|
|
@ -15,21 +15,30 @@
|
|||
*/
|
||||
package ghidra.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.Pointer;
|
||||
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 Boolean signed;
|
||||
public String kind;
|
||||
public String endian;
|
||||
public IsfObject type;
|
||||
|
||||
public IsfTypedefPointer() {
|
||||
PointerDataType ptr = new PointerDataType();
|
||||
size = ptr.getLength();
|
||||
signed = false; //IsfUtilities.getSigned(ptr);
|
||||
kind = IsfUtilities.getBuiltInKind(ptr);
|
||||
public IsfTypedefPointer(TypeDef typeDef) {
|
||||
super(typeDef);
|
||||
Pointer ptr;
|
||||
if (typeDef != null) {
|
||||
ptr = (Pointer) typeDef.getBaseDataType();
|
||||
}
|
||||
else {
|
||||
ptr = new PointerDataType();
|
||||
}
|
||||
size = ptr.hasLanguageDependantLength() ? -1 : ptr.getLength();
|
||||
kind = "typedef";
|
||||
endian = IsfUtilities.getEndianness(ptr);
|
||||
type = new IsfPointer(ptr);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,19 +15,19 @@
|
|||
*/
|
||||
package ghidra.program.model.data.ISF;
|
||||
|
||||
import ghidra.program.model.data.DataType;
|
||||
import ghidra.program.model.data.TypeDef;
|
||||
|
||||
public class IsfTypedefUser implements IsfObject {
|
||||
public class IsfTypedefUser extends AbstractIsfObject {
|
||||
|
||||
public Integer size;
|
||||
public String kind;
|
||||
public IsfObject type;
|
||||
|
||||
public IsfTypedefUser(TypeDef typeDef, IsfObject typeObj) {
|
||||
DataType baseType = typeDef.getBaseDataType();
|
||||
super(typeDef);
|
||||
size = typeDef.getLength();
|
||||
kind = IsfUtilities.getKind(baseType);
|
||||
kind = "typedef";
|
||||
//kind = IsfUtilities.getKind(baseType);
|
||||
type = typeObj;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,46 +20,6 @@ import ghidra.program.model.data.Enum;
|
|||
|
||||
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) {
|
||||
while (dt != null) {
|
||||
if (dt instanceof Array) {
|
||||
|
@ -117,7 +77,7 @@ public class IsfUtilities {
|
|||
return "enum";
|
||||
}
|
||||
if (dt instanceof TypeDef) {
|
||||
return "base"; //"typedef";
|
||||
return "typedef";
|
||||
}
|
||||
if (dt instanceof FunctionDefinition) {
|
||||
return "function";
|
||||
|
@ -133,7 +93,7 @@ public class IsfUtilities {
|
|||
|
||||
public static String getBuiltInKind(BuiltInDataType dt) {
|
||||
if (dt instanceof AbstractIntegerDataType) {
|
||||
return dt.getLength() == 1 ? "char" : "int";
|
||||
return dt.getName();
|
||||
}
|
||||
if (dt instanceof AbstractFloatDataType) {
|
||||
return "float";
|
||||
|
@ -145,7 +105,7 @@ public class IsfUtilities {
|
|||
return "char"; // "string";
|
||||
}
|
||||
if (dt instanceof PointerDataType) {
|
||||
return "void"; //"pointer";
|
||||
return "pointer";
|
||||
}
|
||||
if (dt instanceof VoidDataType) {
|
||||
return "void";
|
||||
|
@ -185,11 +145,48 @@ public class IsfUtilities {
|
|||
return dt.getLength();
|
||||
}
|
||||
|
||||
public static Boolean getSigned(DataType dt) {
|
||||
return dt.getDataOrganization().isSignedChar();
|
||||
}
|
||||
|
||||
public static String getEndianness(DataType dt) {
|
||||
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;
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -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/SplitMemoryBlock.png||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/Navigation/Navigation.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/Navigation/images/GoToDialog.png||GHIDRA||||END|
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
<LI><A href="#binary">Raw Bytes</A></LI>
|
||||
|
||||
<LI><A href="#xml">XML Export Format</A></LI>
|
||||
|
||||
<LI><A href="#sarif">SARIF Export Format</A></LI>
|
||||
</UL>
|
||||
|
||||
<H2>Export Action</H2>
|
||||
|
@ -414,6 +416,18 @@
|
|||
XML Options are identical the <A href=
|
||||
"help/topics/ImporterPlugin/importer.htm#xml_options">XML Importer Options</A>.</I></P>
|
||||
</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>
|
||||
|
||||
<P class="relatedtopic">Related Topics:</P>
|
||||
|
|
|
@ -51,6 +51,7 @@
|
|||
<LI>Raw Binary</LI>
|
||||
<LI>Relocatable Object Module Format (OMF)</LI>
|
||||
<LI>XML Input Format</LI>
|
||||
<LI>SARIF Input Format</LI>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
@ -680,6 +681,16 @@
|
|||
Names</A>.</P>
|
||||
</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>
|
||||
|
||||
<H2><A name="Library_Paths"></A>Library Search Path</H2>
|
||||
|
|
|
@ -64,8 +64,12 @@ import ghidra.util.task.*;
|
|||
public class ExporterDialog extends DialogComponentProvider implements AddressFactoryService {
|
||||
|
||||
private static final String XML_WARNING =
|
||||
" Warning: XML is lossy and intended only for transfering data to external tools. " +
|
||||
"GZF is the recommended format for saving and sharing program data.";
|
||||
" Warning: XML is lossy and intended only for transfering data to external tools. " +
|
||||
"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
|
||||
|
||||
|
@ -394,6 +398,9 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa
|
|||
if (getSelectedExporter().getName().contains("XML")) {
|
||||
setStatusText(XML_WARNING);
|
||||
}
|
||||
if (getSelectedExporter().getName().contains("SARIF")) {
|
||||
setStatusText(SARIF_WARNING);
|
||||
}
|
||||
setOkEnabled(true);
|
||||
}
|
||||
|
||||
|
|
|
@ -470,7 +470,7 @@ public class CodeManagerTest extends AbstractGenericTest {
|
|||
Instruction inst = listing.getInstructionAt(addr(0x1100));
|
||||
inst.setProperty("Numbers", 12);
|
||||
|
||||
PropertyMap map = listing.getPropertyMap("Numbers");
|
||||
PropertyMap<?> map = listing.getPropertyMap("Numbers");
|
||||
assertNotNull(map);
|
||||
|
||||
inst.setProperty("FavoriteColor", new SaveableColor(Palette.RED));
|
||||
|
|
1
Ghidra/Features/Sarif/Module.manifest
Normal file
1
Ghidra/Features/Sarif/Module.manifest
Normal file
|
@ -0,0 +1 @@
|
|||
MODULE FILE LICENSE: lib/java-sarif-2.1.jar MIT
|
36
Ghidra/Features/Sarif/build.gradle
Normal file
36
Ghidra/Features/Sarif/build.gradle
Normal 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"
|
||||
}
|
||||
|
6
Ghidra/Features/Sarif/certification.manifest
Normal file
6
Ghidra/Features/Sarif/certification.manifest
Normal 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|
|
2
Ghidra/Features/Sarif/data/ExtensionPoint.manifest
Normal file
2
Ghidra/Features/Sarif/data/ExtensionPoint.manifest
Normal file
|
@ -0,0 +1,2 @@
|
|||
RunHandler
|
||||
ResultHandler
|
56
Ghidra/Features/Sarif/src/main/help/help/TOC_Source.xml
Normal file
56
Ghidra/Features/Sarif/src/main/help/help/TOC_Source.xml
Normal 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>
|
|
@ -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> </P>
|
||||
</BODY>
|
||||
</HTML>
|
13
Ghidra/Features/Sarif/src/main/java/sarif/DEVNOTES.txt
Normal file
13
Ghidra/Features/Sarif/src/main/java/sarif/DEVNOTES.txt
Normal 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.
|
289
Ghidra/Features/Sarif/src/main/java/sarif/SarifController.java
Normal file
289
Ghidra/Features/Sarif/src/main/java/sarif/SarifController.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
350
Ghidra/Features/Sarif/src/main/java/sarif/SarifLoader.java
Normal file
350
Ghidra/Features/Sarif/src/main/java/sarif/SarifLoader.java
Normal 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;
|
||||
}
|
||||
}
|
250
Ghidra/Features/Sarif/src/main/java/sarif/SarifPlugin.java
Normal file
250
Ghidra/Features/Sarif/src/main/java/sarif/SarifPlugin.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
72
Ghidra/Features/Sarif/src/main/java/sarif/SarifUtils.java
Normal file
72
Ghidra/Features/Sarif/src/main/java/sarif/SarifUtils.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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";
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
// }
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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 = "<";
|
||||
private static final String GREATER_THAN = ">";
|
||||
private static final String APOSTROPHE = "'";
|
||||
private static final String QUOTE = """;
|
||||
private static final String AMPERSAND = "&";
|
||||
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue