GP-3222: Adds ability to export/serve symbols & types as Volatility ISF

JSON
This commit is contained in:
d-millar
2023-04-21 11:31:47 -04:00
committed by Ryan Kurtz
parent 7891d26115
commit 94166ac349
43 changed files with 2802 additions and 3 deletions
@@ -1 +0,0 @@
MODULE FILE LICENSE: lib/protobuf-java-3.21.8.jar BSD-3-GOOGLE
-1
View File
@@ -59,7 +59,6 @@ dependencies {
}
}
api 'com.google.protobuf:protobuf-java:3.21.8'
api project(':Framework-AsyncComm')
api project(':Framework-Debugging')
api project(':ProposedUtils')
@@ -1,3 +1,2 @@
##VERSION: 2.0
##MODULE IP: BSD-3-GOOGLE
Module.manifest||GHIDRA||||END|
+108
View File
@@ -0,0 +1,108 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
apply from: "${rootProject.projectDir}/gradle/javaProject.gradle"
apply from: "${rootProject.projectDir}/gradle/jacocoProject.gradle"
apply from: "${rootProject.projectDir}/gradle/javaTestProject.gradle"
apply from: "${rootProject.projectDir}/gradle/distributableGhidraModule.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Debug Debugger-isf'
configurations {
allProtocArtifacts
protocArtifact
}
def platform = getCurrentPlatformName()
dependencies {
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:windows-x86_64@exe'
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:linux-x86_64@exe'
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:linux-aarch_64@exe'
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:osx-x86_64@exe'
allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:osx-aarch_64@exe'
if (isCurrentWindows()) {
protocArtifact 'com.google.protobuf:protoc:3.21.8:windows-x86_64@exe'
}
if (isCurrentLinux()) {
if (platform.endsWith("x86_64")) {
protocArtifact 'com.google.protobuf:protoc:3.21.8:linux-x86_64@exe'
}
else {
protocArtifact 'com.google.protobuf:protoc:3.21.8:linux-aarch_64@exe'
}
}
if (isCurrentMac()) {
if (platform.endsWith("x86_64")) {
protocArtifact 'com.google.protobuf:protoc:3.21.8:osx-x86_64@exe'
}
else {
protocArtifact 'com.google.protobuf:protoc:3.21.8:osx-aarch_64@exe'
}
}
api project(':Framework-AsyncComm')
api project(':Framework-Debugging')
api project(':ProposedUtils')
testImplementation project(path: ':Framework-AsyncComm', configuration: 'testArtifacts')
testImplementation project(path: ':Framework-Debugging', configuration: 'testArtifacts')
}
task generateProto {
ext.srcdir = file("src/main/proto")
ext.src = fileTree(srcdir) {
include "**/*.proto"
}
ext.outdir = file("build/generated/source/proto/main/java")
outputs.dir(outdir)
inputs.files(src)
dependsOn(configurations.protocArtifact)
doLast {
def exe = configurations.protocArtifact.first()
if (!isCurrentWindows()) {
exe.setExecutable(true)
}
exec {
commandLine exe, "--java_out=$outdir", "-I$srcdir"
args src
}
}
}
tasks.compileJava.dependsOn(tasks.generateProto)
tasks.eclipse.dependsOn(tasks.generateProto)
rootProject.tasks.prepDev.dependsOn(tasks.generateProto)
sourceSets {
main {
java {
srcDir tasks.generateProto.outdir
}
}
}
zipSourceSubproject.dependsOn generateProto
// Include buildable native source in distribution
rootProject.assembleDistribution {
from (this.project.projectDir.toString()) {
include "runISFServer"
into { getZipPath(this.project) }
}
}
@@ -0,0 +1,3 @@
##VERSION: 2.0
Module.manifest||GHIDRA||||END|
runISFServer||GHIDRA||||END|
+36
View File
@@ -0,0 +1,36 @@
#!/usr/bin/env bash
#------------------------------------
# Ghidra headless ISF Server launch
#------------------------------------
# Maximum heap memory may be changed if default is inadequate. This will generally be up to 1/4 of
# the physical memory available to the OS. Uncomment MAXMEM setting if non-default value is needed.
MAXMEM=2G
# Launch mode can be changed to one of the following: fg, debug, debug-suspend
LAUNCH_MODE=fg
# Set the debug address to listen on.
# NOTE: This variable is ignored if not launching in a debugging mode.
DEBUG_ADDRESS=127.0.0.1:13002
# Limit the # of garbage collection and JIT compiler threads in case many headless
# instances are run in parallel. By default, Java will assign one thread per core
# which does not scale well on servers with many cores.
VMARG_LIST="-XX:ParallelGCThreads=2 -XX:CICompilerCount=2 "
# Resolve symbolic link if present and get the directory this script lives in.
# NOTE: "readlink -f" is best but works on Linux only, "readlink" will only work if your PWD
# contains the link you are calling (which is the best we can do on macOS), and the "echo" is the
# fallback, which doesn't attempt to do anything with links.
SCRIPT_FILE="$(readlink -f "$0" 2>/dev/null || readlink "$0" 2>/dev/null || echo "$0")"
SCRIPT_DIR="${SCRIPT_FILE%/*}"
SUPPORT_DIR="${SCRIPT_DIR}/../../../support"
if ! [ -f "${SUPPORT_DIR}/launch.properties" ]; then
SUPPORT_DIR="${SCRIPT_DIR}/../../RuntimeScripts/Linux/support"
fi
# Launch ISF Server.
# DEBUG_ADDRESS set via environment for launch.sh
DEBUG_ADDRESS=${DEBUG_ADDRESS} "${SUPPORT_DIR}"/launch.sh "${LAUNCH_MODE}" jdk Ghidra-ISF "${MAXMEM}" "${VMARG_LIST}" ghidra.dbg.isf.IsfServerLauncher "$@"
@@ -0,0 +1,305 @@
/* ###
* 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.*;
import java.lang.reflect.Constructor;
import java.util.*;
import java.util.Map.Entry;
import javax.swing.tree.TreePath;
import com.google.gson.JsonObject;
import docking.ActionContext;
import docking.action.DockingAction;
import docking.action.MenuData;
import docking.widgets.OptionDialog;
import docking.widgets.filechooser.GhidraFileChooser;
import docking.widgets.tree.GTree;
import docking.widgets.tree.GTreeNode;
import ghidra.app.plugin.core.datamgr.DataTypeManagerPlugin;
import ghidra.app.plugin.core.datamgr.DataTypesActionContext;
import ghidra.app.plugin.core.datamgr.tree.CategoryNode;
import ghidra.app.plugin.core.datamgr.tree.DataTypeNode;
import ghidra.framework.preferences.Preferences;
import ghidra.program.model.data.*;
import ghidra.program.model.data.ISF.IsfDataTypeWriter;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.classfinder.ClassSearcher;
import ghidra.util.exception.CancelledException;
import ghidra.util.filechooser.ExtensionFileFilter;
import ghidra.util.task.*;
// This action was originally referenced by DataTypeProvider::createLocalActions to support testing.
// It may (?) be of general use at some point, but including it in the original location introduces
// a dependency on this project, which seems undesirable right now.
public class ExportToIsfAction extends DockingAction {
private static final String LAST_DATA_TYPE_EXPORT_DIRECTORY = "LAST_DATA_TYPE_EXPORT_DIRECTORY";
private final DataTypeManagerPlugin plugin;
public ExportToIsfAction(DataTypeManagerPlugin plugin) {
super("Export Data Types (ISF)", plugin.getName());
this.plugin = plugin;
setPopupMenuData(new MenuData(new String[] { "Export to ISF..." }, null, "VeryLast"));
setEnabled(true);
}
@Override
public boolean isEnabledForContext(ActionContext context) {
if (!(context instanceof DataTypesActionContext)) {
return false;
}
Object contextObject = context.getContextObject();
GTree gtree = (GTree) contextObject;
TreePath[] selectionPaths = gtree.getSelectionPaths();
for (TreePath path : selectionPaths) {
GTreeNode node = (GTreeNode) path.getLastPathComponent();
if (!isValidNode(node)) {
return false;
}
}
return true;
}
private boolean isValidNode(GTreeNode node) {
if (node instanceof CategoryNode) {
CategoryNode categoryNode = (CategoryNode) node;
return categoryNode.isEnabled();
}
else if (node instanceof DataTypeNode) {
return true;
}
return false;
}
@Override
public void actionPerformed(ActionContext context) {
DataTypesActionContext dtActionContext = (DataTypesActionContext) context;
GTree gTree = (GTree) dtActionContext.getContextObject();
Program program = dtActionContext.getProgram();
if (program == null) {
Msg.showError(this, gTree, "Archive Export Failed",
"A suitable program must be open and activated before\n" +
"an archive export may be performed.");
return;
}
if (OptionDialog.showYesNoDialog(gTree, "Confirm Archive Export",
"Export selected archive(s) using program " + program.getName() +
"'s compiler specification?") != OptionDialog.YES_OPTION) {
return;
}
exportToIsf(gTree, program.getDataTypeManager());
}
/**
* Writes the selection out to a file of the user's choosing. One file will be written for each
* DataTypeManager in the selection.
*
* @param gTree The tree that contains the selected nodes.
*/
private void exportToIsf(GTree gTree, DataTypeManager programDataTypeMgr) {
List<Class<? extends AnnotationHandler>> classes =
ClassSearcher.getClasses(AnnotationHandler.class);
List<AnnotationHandler> list = new ArrayList<>();
Class<?>[] constructorArgumentTypes = {};
for (Class<? extends AnnotationHandler> clazz : classes) {
if (clazz == DefaultAnnotationHandler.class) {
continue;
}
try {
Constructor<?> constructor = clazz.getConstructor(constructorArgumentTypes);
Object obj = constructor.newInstance();
list.add(AnnotationHandler.class.cast(obj));
}
catch (Exception e) {
Msg.showError(this, plugin.getTool().getToolFrame(), "Export Data Types",
"Error creating " + clazz.getName() + "\n" + e.toString(), e);
}
}
AnnotationHandler handler = null;
if (!list.isEmpty()) {
list.add(0, new DefaultAnnotationHandler());
AnnotationHandlerDialog dlg = new AnnotationHandlerDialog(list);
plugin.getTool().showDialog(dlg);
if (!dlg.wasSuccessful()) {
return;
}
handler = dlg.getHandler();
}
else {
handler = new DefaultAnnotationHandler();
}
TreePath[] paths = gTree.getSelectionPaths();
Map<DataTypeManager, List<DataType>> managersToDataTypesMap = new HashMap<>();
for (TreePath path : paths) {
addToManager(path, managersToDataTypesMap);
}
GhidraFileChooser fileChooser = new GhidraFileChooser(gTree);
// filter the files if we can
String[] fileExtensions = handler.getFileExtensions();
if (fileExtensions.length > 0) {
fileChooser.setFileFilter(
new ExtensionFileFilter(fileExtensions, handler.getLanguageName() + " Files"));
}
Set<Entry<DataTypeManager, List<DataType>>> entrySet = managersToDataTypesMap.entrySet();
for (Entry<DataTypeManager, List<DataType>> entry : entrySet) {
DataTypeManager dataTypeManager = entry.getKey();
File file = getFile(gTree, fileChooser, dataTypeManager, handler);
if (file == null) {
return; // user cancelled
}
List<DataType> dataTypeList = entry.getValue();
new TaskLauncher(
new DataTypeWriterTask(gTree, programDataTypeMgr, dataTypeList, file),
gTree);
}
fileChooser.dispose();
}
private 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,
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() + "...");
IsfDataTypeWriter dataTypeWriter =
new IsfDataTypeWriter(programDataTypeMgr, new FileWriter(file));
try {
for (DataType dataType : dataTypeList) {
dataTypeWriter.requestType(dataType);
}
JsonObject object = dataTypeWriter.getRootObject(monitor);
dataTypeWriter.write(object);
}
finally {
dataTypeWriter.close();
}
plugin.getTool()
.setStatusInfo(
"Successfully exported data type(s) to " + file.getAbsolutePath());
}
catch (CancelledException e) {
// user cancelled; ignore
}
catch (IOException e) {
Msg.showError(getClass(), gTree, "Export Data Types Failed",
"Error exporting Data Types: " + e);
return;
}
}
}
private void addToManager(TreePath path,
Map<DataTypeManager, List<DataType>> managersToDataTypesMap) {
Object last = path.getLastPathComponent();
if (last instanceof DataTypeNode) {
DataTypeNode node = (DataTypeNode) last;
DataType dataType = node.getDataType();
DataTypeManager dataTypeManager = dataType.getDataTypeManager();
List<DataType> dataTypeList = managersToDataTypesMap.get(dataTypeManager);
if (dataTypeList == null) {
dataTypeList = new ArrayList<>();
managersToDataTypesMap.put(dataTypeManager, dataTypeList);
}
dataTypeList.add(dataType);
}
else if (last instanceof CategoryNode) {
CategoryNode node = (CategoryNode) last;
List<GTreeNode> children = node.getChildren();
for (GTreeNode cnode : children) {
addToManager(cnode.getTreePath(), managersToDataTypesMap);
}
}
}
private File getFile(GTree gTree, GhidraFileChooser fileChooser,
DataTypeManager dataTypeManager, AnnotationHandler handler) {
fileChooser.setTitle("Select File For Export: " + dataTypeManager.getName());
fileChooser.setSelectedFile(null);
String defaultExtendsionSuffix = ".json";
String lastDirSelected = Preferences.getProperty(LAST_DATA_TYPE_EXPORT_DIRECTORY);
if (lastDirSelected != null) {
File file = new File(lastDirSelected);
if (file.exists()) {
fileChooser.setCurrentDirectory(file);
}
}
fileChooser.rescanCurrentDirectory(); // pick up any recently added archives
File currentDirectory = fileChooser.getCurrentDirectory();
File newFile =
new File(currentDirectory, dataTypeManager.getName() + defaultExtendsionSuffix);
fileChooser.setSelectedFile(newFile);
// show the chooser
File file = fileChooser.getSelectedFile();
if (file == null) {
return null;
}
if (file.exists()) {
if (OptionDialog.showYesNoDialog(gTree, "Overwrite Existing File?",
"Do you want to overwrite the existing file \"" + file.getAbsolutePath() +
"\"?") == OptionDialog.OPTION_TWO) {
return null;
}
}
// save the directory off for the next export
Preferences.setProperty(LAST_DATA_TYPE_EXPORT_DIRECTORY, file.getAbsolutePath());
return file;
}
}
@@ -0,0 +1,219 @@
/* ###
* 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.dbg.isf;
import java.io.IOException;
import java.io.StringWriter;
import java.util.concurrent.atomic.AtomicInteger;
import com.google.gson.JsonObject;
import ghidra.async.AsyncUtils;
import ghidra.dbg.isf.protocol.Isf;
import ghidra.dbg.isf.protocol.Isf.ErrorCode;
import ghidra.dbg.isf.protocol.Isf.RootMessage;
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.TaskMonitor;
public class IsfClientHandler {
protected static final boolean LOG_ERROR_REPLY_STACKS = false;
protected final static AtomicInteger sequencer = new AtomicInteger();
protected static <T> T errorSendNotify(Throwable e) {
Msg.error(IsfClientHandler.class, "Could not send notification: " + e);
return null;
}
private IsfServer server;
// Keeps strong references and tells level of subscription
public IsfClientHandler(IsfServer server) {
this.server = server;
}
protected Isf.RootMessage buildError(Isf.RootMessage req, ErrorCode code, String message) {
return Isf.RootMessage.newBuilder()
.setSequence(req.getSequence())
.setErrorReply(Isf.ErrorReply.newBuilder().setCode(code).setMessage(message))
.build();
}
protected RootMessage replyError(Isf.RootMessage req, Throwable e) {
Throwable t = AsyncUtils.unwrapThrowable(e);
if (LOG_ERROR_REPLY_STACKS) {
Msg.debug(this, "Error caused by request " + req, e);
}
else {
Msg.debug(this, "Error caused by request " + req + ": " + e);
}
if (t instanceof UnsupportedOperationException) {
return buildError(req, ErrorCode.EC_NOT_SUPPORTED, t.getMessage());
}
return buildError(req, ErrorCode.EC_UNKNOWN, "Unknown server-side error");
}
protected String getVersion() {
return "V1";
}
protected RootMessage processMessage(Isf.RootMessage msg) throws IOException {
switch (msg.getMsgCase()) {
case PING_REQUEST:
return processPing(msg.getSequence(), msg.getPingRequest());
case FULL_EXPORT_REQUEST:
return processFullExport(msg.getSequence(), msg.getFullExportRequest());
case LOOK_TYPE_REQUEST:
return processLookType(msg.getSequence(), msg.getLookTypeRequest());
case LOOK_SYMBOL_REQUEST:
return processLookSym(msg.getSequence(), msg.getLookSymbolRequest());
case LOOK_ADDRESS_REQUEST:
return processLookAddr(msg.getSequence(), msg.getLookAddressRequest());
case ENUM_TYPES_REQUEST:
return processEnumTypes(msg.getSequence(), msg.getEnumTypesRequest());
case ENUM_SYMBOLS_REQUEST:
return processEnumSyms(msg.getSequence(), msg.getEnumSymbolsRequest());
default:
throw new IsfErrorException(Isf.ErrorCode.EC_BAD_REQUEST,
"Unrecognized request: " + msg.getMsgCase());
}
}
protected RootMessage processPing(int seqno, Isf.PingRequest req) {
return Isf.RootMessage.newBuilder()
.setSequence(seqno)
.setPingReply(Isf.PingReply.newBuilder().setContent(req.getContent()))
.build();
}
protected RootMessage processFullExport(int seqno, Isf.FullExportRequest req)
throws IOException {
String data = fullExport(req.getNs());
return Isf.RootMessage.newBuilder()
.setSequence(seqno)
.setFullExportReply(Isf.FullExportReply.newBuilder()
.setValue(data))
.build();
}
private String fullExport(String ns) throws IOException {
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
return writeFrom(isfWriter);
}
protected RootMessage processLookType(int seqno, Isf.LookTypeRequest req) throws IOException {
String data = lookType(req.getNs(), req.getKey());
return Isf.RootMessage.newBuilder()
.setSequence(seqno)
.setLookTypeReply(Isf.LookTypeReply.newBuilder()
.setValue(data))
.build();
}
private String lookType(String ns, String key) throws IOException {
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
isfWriter.setSkipSymbols(true);
isfWriter.requestType(key);
return writeFrom(isfWriter);
}
protected RootMessage processLookSym(int seqno, Isf.LookSymRequest req) throws IOException {
String data = lookSym(req.getNs(), req.getKey());
return Isf.RootMessage.newBuilder()
.setSequence(seqno)
.setLookSymbolReply(Isf.LookSymReply.newBuilder()
.setValue(data))
.build();
}
private String lookSym(String ns, String key) throws IOException {
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
isfWriter.setSkipTypes(true);
isfWriter.requestSymbol(key);
return writeFrom(isfWriter);
}
protected RootMessage processLookAddr(int seqno, Isf.LookAddrRequest req) throws IOException {
String data = lookAddr(req.getNs(), req.getKey());
return Isf.RootMessage.newBuilder()
.setSequence(seqno)
.setLookAddressReply(Isf.LookAddrReply.newBuilder()
.setValue(data))
.build();
}
private String lookAddr(String ns, String key) throws IOException {
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
isfWriter.setSkipTypes(true);
isfWriter.requestAddress(key);
return writeFrom(isfWriter);
}
protected RootMessage processEnumTypes(int seqno, Isf.EnumTypesRequest req) throws IOException {
String data = enumTypes(req.getNs());
return Isf.RootMessage.newBuilder()
.setSequence(seqno)
.setEnumTypesReply(Isf.EnumTypesReply.newBuilder()
.setValue(data))
.build();
}
private String enumTypes(String ns) throws IOException {
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
isfWriter.setSkipSymbols(true);
return writeFrom(isfWriter);
}
protected RootMessage processEnumSyms(int seqno, Isf.EnumSymsRequest req) throws IOException {
String data = enumSyms(req.getNs());
return Isf.RootMessage.newBuilder()
.setSequence(seqno)
.setEnumSymbolsReply(Isf.EnumSymsReply.newBuilder()
.setValue(data))
.build();
}
private String enumSyms(String ns) throws IOException {
IsfDataTypeWriter isfWriter = createDataTypeWriter(server.getDataTypeManager(ns));
isfWriter.setSkipTypes(true);
return writeFrom(isfWriter);
}
private IsfDataTypeWriter createDataTypeWriter(DataTypeManager dtm) throws IOException {
StringWriter out = new StringWriter();
return new IsfDataTypeWriter(dtm, out);
}
private String writeFrom(IsfDataTypeWriter dataTypeWriter) throws IOException {
try {
JsonObject object =
dataTypeWriter.getRootObject(TaskMonitor.DUMMY);
dataTypeWriter.write(object);
}
catch (CancelledException e) {
// NOTHING
}
finally {
dataTypeWriter.close();
}
return dataTypeWriter.toString();
}
}
@@ -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 ghidra.dbg.isf;
import java.io.*;
import java.net.Socket;
import com.google.protobuf.AbstractMessage;
import ghidra.dbg.isf.protocol.Isf.RootMessage;
import ghidra.util.Msg;
public class IsfConnectionHandler extends Thread {
private Socket socket;
private IsfClientHandler handler;
public IsfConnectionHandler(Socket socket, IsfClientHandler handler) {
this.socket = socket;
this.handler = handler;
}
@Override
public void run() {
try {
Msg.info(this, "Handler started...");
InputStream inputStream = socket.getInputStream();
while (!socket.isClosed()) {
RootMessage root = RootMessage.parseDelimitedFrom(inputStream);
if (root != null) {
AbstractMessage msg = handler.processMessage(root);
OutputStream out = socket.getOutputStream();
msg.writeDelimitedTo(out);
out.flush();
}
}
}
catch (IOException e) {
Msg.error(this, e);
}
}
}
@@ -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 ghidra.dbg.isf;
import ghidra.dbg.isf.protocol.Isf.ErrorCode;
public class IsfErrorException extends RuntimeException {
private ErrorCode code;
public IsfErrorException(ErrorCode code, String message) {
super(code + ": " + message);
this.code = code;
}
public ErrorCode getCode() {
return code;
}
}
@@ -0,0 +1,174 @@
/* ###
* 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.dbg.isf;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;
import db.DBConstants;
import db.DBHandle;
import generic.test.AbstractGTest;
import ghidra.GhidraApplicationLayout;
import ghidra.GhidraTestApplicationLayout;
import ghidra.base.project.GhidraProject;
import ghidra.framework.Application;
import ghidra.framework.GhidraApplicationConfiguration;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.ProjectData;
import ghidra.framework.store.db.PackedDatabase;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.FileDataTypeManager;
import ghidra.program.model.listing.Program;
import ghidra.util.Msg;
import ghidra.util.exception.VersionException;
import ghidra.util.task.TaskMonitor;
public class IsfServer extends Thread {
private ServerSocket server;
private boolean running = false;
private GhidraProject project;
private int port = 54321;
private IsfClientHandler handler;
private Map<String, DataTypeManager> managers = new HashMap<>();
public IsfServer(GhidraProject project, int port) {
this.project = project;
this.port = port;
handler = new IsfClientHandler(this);
}
public void startServer() {
try {
server = new ServerSocket(port);
this.start();
}
catch (IOException e) {
throw new RuntimeException("Could not start server");
}
}
public void stopServer() {
running = false;
this.interrupt();
for (DataTypeManager m : managers.values()) {
m.close();
}
}
@Override
public void run() {
running = true;
while (running) {
try {
Msg.info(this, "Listening for a connection...");
Socket socket = server.accept();
socket.setTcpNoDelay(true);
Msg.info(this, "Connected - starting handler...");
IsfConnectionHandler connectionHandler = new IsfConnectionHandler(socket, handler);
connectionHandler.start();
}
catch (IOException e) {
Msg.error(this, e);
}
}
}
public DataTypeManager getDataTypeManager(String ns) {
synchronized (managers) {
if (managers.containsKey(ns)) {
return managers.get(ns);
}
try {
DataTypeManager dtm;
if (ns.endsWith(".gdt")) {
dtm = openAsArchive(ns);
}
else if (ns.endsWith(".gzf")) {
dtm = openAsDatabase(ns);
}
else {
dtm = openAsDomainFile(ns);
}
managers.put(ns, dtm);
return dtm;
}
catch (Exception e) {
Msg.error(this, ns + " undefined namespace (should be .gdt, .gzf, or domain file)");
return null;
}
}
}
private DataTypeManager openAsDomainFile(String ns) throws Exception {
ProjectData projectData = project.getProjectData();
DomainFile df = projectData.getFile(ns);
Program program = (Program) df.getDomainObject(this, false, false, TaskMonitor.DUMMY);
return program.getDataTypeManager();
}
private DataTypeManager openAsArchive(String ns) throws Exception {
File gdt = new File(ns);
return FileDataTypeManager.openFileArchive(gdt, false);
}
private DataTypeManager openAsDatabase(String ns) throws Exception {
File gzf = new File(ns);
TaskMonitor dummy = TaskMonitor.DUMMY;
PackedDatabase db = PackedDatabase.getPackedDatabase(gzf, dummy);
DBHandle dbh = db.openForUpdate(dummy);
ProgramDB p = null;
try {
p = new ProgramDB(dbh, DBConstants.UPDATE, dummy, this);
}
catch (VersionException e) {
if (!e.isUpgradable()) {
throw new RuntimeException(p + " uses an older version and is not upgradable.");
}
}
finally {
dbh.close();
}
dbh = db.openForUpdate(dummy);
p = new ProgramDB(dbh, DBConstants.UPGRADE, dummy, this);
if (!p.isChanged()) {
throw new RuntimeException(p + " uses an older version and was not upgraded.");
}
return p.getListing().getDataTypeManager();
}
public static void main(String[] args) throws FileNotFoundException, IOException {
GhidraApplicationLayout layout = new GhidraTestApplicationLayout(
new File(AbstractGTest.getTestDirectoryPath()));
GhidraApplicationConfiguration config = new GhidraApplicationConfiguration();
config.setShowSplashScreen(false);
Application.initializeApplication(layout, config);
IsfServer server = new IsfServer(null, 54321);
server.startServer();
}
}
@@ -0,0 +1,86 @@
/* ###
* 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.dbg.isf;
import java.io.File;
import java.io.IOException;
import ghidra.GhidraApplicationLayout;
import ghidra.GhidraLaunchable;
import ghidra.base.project.GhidraProject;
import ghidra.framework.*;
import ghidra.framework.model.ProjectLocator;
import ghidra.util.Msg;
// To be run using runISFServer
public class IsfServerLauncher implements GhidraLaunchable {
private GhidraProject project = null;
private IsfServer server;
private int port;
@Override
public void launch(GhidraApplicationLayout layout, String[] args) throws Exception {
ApplicationConfiguration config = new HeadlessGhidraApplicationConfiguration();
if (!Application.isInitialized()) {
Application.initializeApplication(layout, config);
}
GhidraProject proj = parseArgs(args);
server = new IsfServer(proj, port);
server.startServer();
}
GhidraProject parseArgs(String[] args) throws IOException {
if (args != null && args.length < 1) {
usage();
return null;
}
port = Integer.parseInt(args[0]);
if (args.length > 1) {
String projectLocation = args[1];
String projectName = args[2];
File dir = new File(projectLocation);
if (dir.exists()) {
ProjectLocator locator = new ProjectLocator(dir.getAbsolutePath(), projectName);
if (locator.getProjectDir().exists()) {
project = GhidraProject.openProject(projectLocation, projectName);
}
}
}
return project;
}
public int getPort() {
return port;
}
public void close() {
server.stopServer();
if (project != null) {
project.close();
}
}
public void usage() {
Msg.error(this, "Usage: runISFServer <port> <project_location> <project_name> ");
}
}
@@ -0,0 +1,34 @@
/* ###
* 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.BuiltInDataType;
public class IsfBuiltIn implements IsfObject {
public Integer size;
public Boolean signed;
public String kind;
public String endian;
public IsfBuiltIn(BuiltInDataType builtin) {
size = IsfUtilities.getLength(builtin);
signed = IsfUtilities.getSigned(builtin);
kind = IsfUtilities.getBuiltInKind(builtin);
endian = IsfUtilities.getEndianness(builtin);
}
}
@@ -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 ghidra.program.model.data.ISF;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude;
public class IsfComponent implements IsfObject {
public Integer offset;
public IsfObject type;
@Exclude
public int ordinal;
@Exclude
public int length;
@Exclude
public String field_name;
@Exclude
public String comment;
public IsfComponent(DataTypeComponent component, IsfObject typeObj) {
offset = component.getOffset();
type = typeObj;
field_name = component.getFieldName();
ordinal = component.getOrdinal();
length = component.getLength();
comment = component.getComment();
}
}
@@ -0,0 +1,66 @@
/* ###
* 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.*;
import com.google.gson.JsonObject;
import ghidra.program.model.data.*;
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude;
import ghidra.util.task.TaskMonitor;
public class IsfComposite implements IsfObject {
public String kind;
public Integer size;
public JsonObject fields;
@Exclude
public int alignment;
public IsfComposite(Composite composite, IsfDataTypeWriter writer, TaskMonitor monitor) {
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);
}
ArrayList<String> keylist = new ArrayList<>(comps.keySet());
Collections.sort(keylist);
fields = new JsonObject();
for (String key : keylist) {
if (monitor.isCancelled()) {
break;
}
DataTypeComponent component = comps.get(key);
IsfObject type = writer.getObjectTypeDeclaration(component);
IsfComponent cobj = new IsfComponent(component, type);
fields.add(key, writer.getTree(cobj));
}
}
}
@@ -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.Array;
public class IsfDataTypeArray implements IsfObject {
public String kind;
public Integer count;
public IsfObject subtype;
public IsfDataTypeArray(Array arr, IsfObject typeObj) {
kind = IsfUtilities.getKind(arr);
count = arr.getNumElements();
subtype = typeObj;
}
}
@@ -0,0 +1,43 @@
/* ###
* 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.BitFieldDataType;
import ghidra.program.model.data.ISF.IsfDataTypeWriter.Exclude;
public class IsfDataTypeBitField implements IsfObject {
public String kind;
public Integer bit_length;
public Integer bit_position;
public IsfObject type;
@Exclude
public Integer bit_offset;
@Exclude
private int storage_size;
public IsfDataTypeBitField(BitFieldDataType bf, int componentOffset, IsfObject typeObj) {
kind = IsfUtilities.getKind(bf);
bit_length = bf.getBitSize();
bit_offset = bf.getBitOffset();
bit_position = componentOffset % 4 * 8 + bit_offset;
type = typeObj;
storage_size = bf.getStorageSize();
}
}
@@ -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;
import ghidra.program.model.data.DataType;
public class IsfDataTypeDefault implements IsfObject {
public String kind;
public String name;
public IsfDataTypeDefault(DataType dt) {
kind = IsfUtilities.getKind(dt);
name = dt.getName();
}
}
@@ -0,0 +1,28 @@
/* ###
* 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 IsfDataTypeNull implements IsfObject {
public String kind;
public String name;
public IsfDataTypeNull() {
kind = "base";
name = "void";
}
}
@@ -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;
import ghidra.program.model.data.DataType;
public class IsfDataTypeTypeDef implements IsfObject {
public String kind;
public IsfObject subtype;
public IsfDataTypeTypeDef(DataType dt, IsfObject typeObj) {
kind = IsfUtilities.getKind(dt);
subtype = typeObj;
}
}
@@ -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.Dynamic;
public class IsfDynamicComponent implements IsfObject {
public String kind;
public Integer count;
public IsfObject subtype;
public IsfDynamicComponent(Dynamic dynamicType, IsfObject type, int elementCnt) {
kind = "array";
subtype = type;
count = elementCnt;
}
}
@@ -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 ghidra.program.model.data.ISF;
import com.google.gson.JsonObject;
import ghidra.program.model.data.Enum;
public class IsfEnum implements IsfObject {
public Integer size;
public String base;
public JsonObject constants = new JsonObject();
public IsfEnum(Enum enumm) {
size = enumm.getLength();
base = "int";
String[] names = enumm.getNames();
for (int j = 0; j < names.length; j++) {
constants.addProperty(names[j], enumm.getValue(names[j]));
}
}
}
@@ -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 ghidra.program.model.data.ISF;
public class IsfFunction implements IsfObject {
public String kind;
public IsfFunction() {
kind = "function";
}
}
@@ -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.DataType;
import ghidra.program.model.data.FunctionDefinition;
public class IsfFunctionPointer implements IsfObject {
public String kind;
public IsfObject subtype;
public IsfFunctionPointer(FunctionDefinition def, DataType dt) {
kind = "pointer";
subtype = new IsfFunction();
//TODO?
}
}
@@ -0,0 +1,34 @@
/* ###
* 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.Map;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
public class IsfLinuxOS implements IsfObject {
public JsonArray symbols = new JsonArray();
public JsonArray types = new JsonArray();
public IsfLinuxOS(Gson gson, Map<String, String> metaData) {
IsfLinuxProgram pgm = new IsfLinuxProgram(metaData);
symbols.add(gson.toJsonTree(pgm));
types.add(gson.toJsonTree(pgm));
}
}
@@ -0,0 +1,34 @@
/* ###
* 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.Map;
public class IsfLinuxProgram implements IsfObject {
public String kind;
public String name;
public String hash_type;
public String hash_value;
public IsfLinuxProgram(Map<String, String> metaData) {
kind = "dwarf";
name = metaData.get("Program Name");
hash_type = "sha256";
hash_value = metaData.get("Executable SHA256");
}
}
@@ -0,0 +1,22 @@
/* ###
* 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 interface IsfObject {
// EMPTY by design
}
@@ -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 ghidra.program.model.data.ISF;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import ghidra.program.model.listing.Program;
public class IsfProducer implements IsfObject {
public String datetime;
public String name;
public String version;
public IsfProducer(Program program) {
Map<String, String> metaData = program.getMetadata();
Date creationDate = program.getCreationDate();
SimpleDateFormat dataFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
datetime = dataFormat.format(creationDate);
name = "Ghidra";
version = metaData.get(Program.CREATED_WITH_GHIDRA_VERSION);
}
}
@@ -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.DataType;
public class IsfTypedObject implements IsfObject {
public String kind;
public Integer size;
public IsfObject type;
public IsfTypedObject(DataType dt, IsfObject typeObj) {
kind = IsfUtilities.getKind(dt);
size = dt.getLength();
type = typeObj;
}
}
@@ -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 ghidra.program.model.data.ISF;
import ghidra.program.model.data.BuiltInDataType;
import ghidra.program.model.data.TypeDef;
public class IsfTypedefBase implements IsfObject {
public Integer size;
public String kind;
public Boolean signed;
public String endian;
public IsfTypedefBase(TypeDef typeDef) {
BuiltInDataType builtin = (BuiltInDataType) typeDef.getBaseDataType();
size = typeDef.getLength();
kind = IsfUtilities.getBuiltInKind(builtin);
signed = IsfUtilities.getSigned(typeDef);
endian = IsfUtilities.getEndianness(typeDef);
}
}
@@ -0,0 +1,28 @@
/* ###
* 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.TypeDef;
public class IsfTypedefIntegral implements IsfObject {
public Integer size;
public IsfTypedefIntegral(TypeDef td) {
size = td.getLength();
}
}
@@ -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 ghidra.program.model.data.ISF;
import ghidra.program.model.data.PointerDataType;
public class IsfTypedefPointer implements IsfObject {
public Integer size;
public Boolean signed;
public String kind;
public String endian;
public IsfTypedefPointer() {
PointerDataType ptr = new PointerDataType();
size = ptr.getLength();
signed = false; //IsfUtilities.getSigned(ptr);
kind = IsfUtilities.getBuiltInKind(ptr);
endian = IsfUtilities.getEndianness(ptr);
}
}
@@ -0,0 +1,34 @@
/* ###
* 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.DataType;
import ghidra.program.model.data.TypeDef;
public class IsfTypedefUser implements IsfObject {
public Integer size;
public String kind;
public IsfObject type;
public IsfTypedefUser(TypeDef typeDef, IsfObject typeObj) {
DataType baseType = typeDef.getBaseDataType();
size = typeDef.getLength();
kind = IsfUtilities.getKind(baseType);
type = typeObj;
}
}
@@ -0,0 +1,195 @@
/* ###
* 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.*;
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) {
Array array = (Array) dt;
dt = array.getDataType();
}
else if (dt instanceof Pointer) {
Pointer pointer = (Pointer) dt;
dt = pointer.getDataType();
}
else if (dt instanceof BitFieldDataType) {
BitFieldDataType bitfieldDt = (BitFieldDataType) dt;
dt = bitfieldDt.getBaseDataType();
}
else {
break;
}
}
return dt;
}
public static DataType getArrayBaseType(Array arrayDt) {
DataType dataType = arrayDt.getDataType();
while (dataType instanceof Array) {
dataType = ((Array) dataType).getDataType();
}
return dataType;
}
public static DataType getPointerBaseDataType(Pointer p) {
DataType dt = p.getDataType();
while (dt instanceof Pointer) {
dt = ((Pointer) dt).getDataType();
}
return dt;
}
public static String getKind(DataType dt) {
if (dt instanceof Array) {
return "array";
}
if (dt instanceof Structure) {
return "struct";
}
if (dt instanceof Union) {
return "union";
}
if (dt instanceof BuiltInDataType) {
return "base";
}
if (dt instanceof Pointer) {
return "pointer";
}
if (dt instanceof Enum) {
return "enum";
}
if (dt instanceof TypeDef) {
return "base"; //"typedef";
}
if (dt instanceof FunctionDefinition) {
return "function";
}
if (dt instanceof BitFieldDataType) {
return "bitfield";
}
if (dt instanceof DefaultDataType) {
return "base";
}
return "UNKNOWN";
}
public static String getBuiltInKind(BuiltInDataType dt) {
if (dt instanceof AbstractIntegerDataType) {
return dt.getLength() == 1 ? "char" : "int";
}
if (dt instanceof AbstractFloatDataType) {
return "float";
}
if (dt instanceof AbstractComplexDataType) {
return "complex";
}
if (dt instanceof AbstractStringDataType) {
return "char"; // "string";
}
if (dt instanceof PointerDataType) {
return "void"; //"pointer";
}
if (dt instanceof VoidDataType) {
return "void";
}
if (dt instanceof Undefined) {
return "void";
}
return "char";
}
public static boolean isBaseDataType(DataType dt) {
if (dt instanceof AbstractIntegerDataType) {
return true;
}
if (dt instanceof AbstractFloatDataType) {
return true;
}
if (dt instanceof AbstractComplexDataType) {
return true;
}
if (dt instanceof AbstractStringDataType) {
return true;
}
if (dt instanceof Pointer) {
return true;
}
if (dt instanceof VoidDataType) {
return true;
}
if (dt instanceof Undefined) {
return true;
}
return false;
}
public static Integer getLength(DataType dt) {
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";
}
}
@@ -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;
import java.util.Map;
public class IsfWinOS implements IsfObject {
public IsfWinPE pe;
public IsfWinPDB pdb;
public IsfWinOS(Map<String, String> metaData) {
pe = new IsfWinPE(metaData);
pdb = new IsfWinPDB(metaData);
}
}
@@ -0,0 +1,34 @@
/* ###
* 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.Map;
public class IsfWinPDB implements IsfObject {
public String GUID;
public Integer age;
public String database;
public Integer machine_type;
public IsfWinPDB(Map<String, String> metaData) {
GUID = metaData.get("PDB GUID");
age = Integer.valueOf(metaData.get("PDB Age"));
database = metaData.get("PDB File");
machine_type = 0; //metaData.get("PDB Version")); //?
}
}
@@ -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 ghidra.program.model.data.ISF;
import java.util.Map;
public class IsfWinPE implements IsfObject {
public Integer build;
public Integer major;
public Integer minor;
public Integer revision;
public IsfWinPE(Map<String, String> metaData) {
String data = metaData.get("PE Property[ProductVersion]");
String[] quad = data.split("\\.");
build = Integer.valueOf(quad[3]);
major = Integer.valueOf(quad[0]);
minor = Integer.valueOf(quad[1]);
revision = Integer.valueOf(quad[2]);
}
}
@@ -0,0 +1,128 @@
/* ###
* 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.
*/
syntax = "proto3";
package ghidra.dbg.isf.protocol;
enum ErrorCode {
EC_UNKNOWN = 0;
EC_BAD_REQUEST = 1;
EC_NOT_SUPPORTED = 2;
}
// For testing: cause the server to report an unrecognized request error
message ErrorRequest {
}
message ErrorReply {
ErrorCode code = 1;
string message = 2;
}
message PingRequest {
string content = 1;
}
message PingReply {
string content = 1;
}
message FullExportRequest {
string ns = 1;
}
message FullExportReply {
string value = 1;
}
message LookAddrRequest {
string ns = 1;
string key = 2;
}
message LookAddrReply {
string value = 1;
}
message LookTypeRequest {
string ns = 1;
string key = 2;
}
message LookTypeReply {
string value = 1;
}
message EnumTypesRequest {
string ns = 1;
}
message EnumTypesReply {
string ns = 1;
string value = 2;
}
message LookSymRequest {
string ns = 1;
string key = 2;
}
message LookSymReply {
string value = 1;
}
message EnumSymsRequest {
string ns = 1;
}
message EnumSymsReply {
string value = 1;
}
message RootAddedEvent {
}
message RootMessage {
int32 sequence = 1;
oneof msg {
ErrorRequest error_request = 100;
ErrorReply error_reply = 200;
PingRequest ping_request = 101;
PingReply ping_reply = 201;
FullExportRequest full_export_request = 102;
FullExportReply full_export_reply = 202;
LookTypeRequest look_type_request = 103;
LookTypeReply look_type_reply = 203;
LookSymRequest look_symbol_request = 104;
LookSymReply look_symbol_reply = 204;
LookAddrRequest look_address_request = 105;
LookAddrReply look_address_reply = 205;
EnumTypesRequest enum_types_request = 106;
EnumTypesReply enum_types_reply = 206;
EnumSymsRequest enum_symbols_request = 107;
EnumSymsReply enum_symbols_reply = 207;
}
}
@@ -0,0 +1 @@
MODULE FILE LICENSE: lib/protobuf-java-3.21.8.jar BSD-3-GOOGLE
@@ -22,6 +22,7 @@ apply plugin: 'eclipse'
eclipse.project.name = 'Debug Framework-AsyncComm'
dependencies {
api 'com.google.protobuf:protobuf-java:3.21.8'
api project(':Generic')
api project(':Graph')
api project(':ProposedUtils')
@@ -1,2 +1,3 @@
##VERSION: 2.0
##MODULE IP: BSD-3-GOOGLE
Module.manifest||GHIDRA||||END|