This is a simple skeleton help topic. For a better description of what should and should not + go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your + favorite help topic. In general, language modules do not have their own help topics.
+ + diff --git a/GhidraPlugin/bin/main/images/README.txt b/GhidraPlugin/bin/main/images/README.txt new file mode 100644 index 00000000..f20ae77b --- /dev/null +++ b/GhidraPlugin/bin/main/images/README.txt @@ -0,0 +1,2 @@ +The "src/resources/images" directory is intended to hold all image/icon files used by +this module. diff --git a/GhidraPlugin/bin/scripts/README.txt b/GhidraPlugin/bin/scripts/README.txt new file mode 100644 index 00000000..9e408f4b --- /dev/null +++ b/GhidraPlugin/bin/scripts/README.txt @@ -0,0 +1 @@ +Java source directory to hold module-specific Ghidra scripts. diff --git a/GhidraPlugin/build.gradle b/GhidraPlugin/build.gradle index 328f0f4e..63365e84 100644 --- a/GhidraPlugin/build.gradle +++ b/GhidraPlugin/build.gradle @@ -1,44 +1,66 @@ -plugins { - id 'java' +/* ### + * 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. + */ +// Builds a Ghidra Extension for a given Ghidra installation. +// +// An absolute path to the Ghidra installation directory must be supplied either by setting the +// GHIDRA_INSTALL_DIR environment variable or Gradle project property: +// +// > export GHIDRA_INSTALL_DIR=This is a simple skeleton help topic. For a better description of what should and should not + go in here, see the "sample" Ghidra extension in the Extensions/Ghidra directory, or see your + favorite help topic. In general, language modules do not have their own help topics.
+ + diff --git a/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginAnalyzer.java b/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginAnalyzer.java new file mode 100644 index 00000000..8718a0d9 --- /dev/null +++ b/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginAnalyzer.java @@ -0,0 +1,74 @@ +/* ### + * 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 ghidraplugin; + +import ghidra.app.services.AbstractAnalyzer; +import ghidra.app.services.AnalyzerType; +import ghidra.app.util.importer.MessageLog; +import ghidra.framework.options.Options; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.listing.Program; +import ghidra.util.exception.CancelledException; +import ghidra.util.task.TaskMonitor; + +/** + * Provide class-level documentation that describes what this analyzer does. + */ +public class GhidraPluginAnalyzer extends AbstractAnalyzer { + + public GhidraPluginAnalyzer() { + + // Name the analyzer and give it a description. + + super("My Analyzer", "Analyzer description goes here", AnalyzerType.BYTE_ANALYZER); + } + + @Override + public boolean getDefaultEnablement(Program program) { + + // Return true if analyzer should be enabled by default + + return true; + } + + @Override + public boolean canAnalyze(Program program) { + + // Examine 'program' to determine of this analyzer should analyze it. Return true + // if it can. + + return true; + } + + @Override + public void registerOptions(Options options, Program program) { + + // If this analyzer has custom options, register them here + + options.registerOption("Option name goes here", false, null, + "Option description goes here"); + } + + @Override + public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) + throws CancelledException { + + // Perform analysis when things get added to the 'program'. Return true if the + // analysis succeeded. + + return false; + } +} diff --git a/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginPlugin.java b/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginPlugin.java new file mode 100644 index 00000000..92ecd6a9 --- /dev/null +++ b/GhidraPlugin/src/main/java/ghidraplugin/GhidraPluginPlugin.java @@ -0,0 +1,116 @@ +/* ### + * 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 ghidraplugin; + +import java.awt.BorderLayout; + +import javax.swing.*; + +import docking.ActionContext; +import docking.ComponentProvider; +import docking.action.DockingAction; +import docking.action.ToolBarData; +import ghidra.app.ExamplesPluginPackage; +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.app.plugin.ProgramPlugin; +import ghidra.framework.plugintool.*; +import ghidra.framework.plugintool.util.PluginStatus; +import ghidra.util.HelpLocation; +import ghidra.util.Msg; +import resources.Icons; + +/** + * Provide class-level documentation that describes what this plugin does. + */ +//@formatter:off +@PluginInfo( + status = PluginStatus.STABLE, + packageName = ExamplesPluginPackage.NAME, + category = PluginCategoryNames.EXAMPLES, + shortDescription = "Plugin short description goes here.", + description = "Plugin long description goes here." +) +//@formatter:on +public class GhidraPluginPlugin extends ProgramPlugin { + + MyProvider provider; + + /** + * Plugin constructor. + * + * @param tool The plugin tool that this plugin is added to. + */ + public GhidraPluginPlugin(PluginTool tool) { + super(tool); + + // Customize provider (or remove if a provider is not desired) + String pluginName = getName(); + provider = new MyProvider(this, pluginName); + + // Customize help (or remove if help is not desired) + String topicName = this.getClass().getPackage().getName(); + String anchorName = "HelpAnchor"; + provider.setHelpLocation(new HelpLocation(topicName, anchorName)); + } + + @Override + public void init() { + super.init(); + + // Acquire services if necessary + } + + // If provider is desired, it is recommended to move it to its own file + private static class MyProvider extends ComponentProvider { + + private JPanel panel; + private DockingAction action; + + public MyProvider(Plugin plugin, String owner) { + super(plugin.getTool(), "Skeleton Provider", owner); + buildPanel(); + createActions(); + } + + // Customize GUI + private void buildPanel() { + panel = new JPanel(new BorderLayout()); + JTextArea textArea = new JTextArea(5, 25); + textArea.setEditable(false); + panel.add(new JScrollPane(textArea)); + setVisible(true); + } + + // Customize actions + private void createActions() { + action = new DockingAction("My Action", getOwner()) { + @Override + public void actionPerformed(ActionContext context) { + Msg.showInfo(getClass(), panel, "Custom Action", "Hello!"); + } + }; + action.setToolBarData(new ToolBarData(Icons.ADD_ICON, null)); + action.setEnabled(true); + action.markHelpUnnecessary(); + dockingTool.addLocalAction(this, action); + } + + @Override + public JComponent getComponent() { + return panel; + } + } +} diff --git a/GhidraPlugin/src/main/java/ghidraplugin/SymbolRenameLoggerPlugin.java b/GhidraPlugin/src/main/java/ghidraplugin/SymbolRenameLoggerPlugin.java new file mode 100644 index 00000000..4f0c3cf6 --- /dev/null +++ b/GhidraPlugin/src/main/java/ghidraplugin/SymbolRenameLoggerPlugin.java @@ -0,0 +1,350 @@ +package ghidraplugin; + +import ghidra.app.plugin.PluginCategoryNames; +import ghidra.app.plugin.ProgramPlugin; +import ghidra.framework.plugintool.PluginInfo; +import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.util.PluginStatus; +import ghidra.program.model.listing.Program; +import ghidra.program.util.ProgramChangeRecord; +import ghidra.program.util.ProgramEvent; +import ghidra.util.Msg; +import ghidra.framework.model.*; +import ghidra.program.model.symbol.*; +import ghidra.program.model.listing.Function; +import ghidra.program.util.*; + +@PluginInfo( + status = PluginStatus.STABLE, + packageName = "SymbolLogger", + category = PluginCategoryNames.COMMON, + shortDescription = "Logs symbol and function renames", + description = "A plugin that monitors and logs all symbol and function rename events to the console", + servicesRequired = {}, + servicesProvided = {} +) +public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObjectListener { + + public SymbolRenameLoggerPlugin(PluginTool tool) { + super(tool); + } + + @Override + protected void init() { + super.init(); + Msg.info(this, "SymbolRenameLoggerPlugin initialized"); + } + + @Override + protected void programActivated(Program program) { + super.programActivated(program); + if (program != null) { + program.addListener(this); + Msg.info(this, "Started listening for rename events in program: " + program.getName()); + } + } + + @Override + protected void programDeactivated(Program program) { + if (program != null) { + program.removeListener(this); + Msg.info(this, "Stopped listening for rename events in program: " + program.getName()); + } + super.programDeactivated(program); + } + + @Override + public void domainObjectChanged(DomainObjectChangedEvent ev) { + for (DomainObjectChangeRecord record : ev) { + if (record instanceof ProgramChangeRecord) { + ProgramChangeRecord progRecord = (ProgramChangeRecord) record; + handleProgramChange(progRecord); + } + } + } + + private void handleProgramChange(ProgramChangeRecord record) { + ProgramEvent eventType = (ProgramEvent)record.getEventType(); + + // Handle symbol rename events + if (eventType == ProgramEvent.SYMBOL_RENAMED) { + handleSymbolRenamed(record); + } + // Handle function rename events (functions are also symbols, but we can be more specific) + else if (eventType == ProgramEvent.FUNCTION_CHANGED) { + handleFunctionChanged(record); + } + // Handle symbol added events (in case we want to track new symbols) + else if (eventType == ProgramEvent.SYMBOL_ADDED) { + handleSymbolAdded(record); + } + // Handle symbol removed events + else if (eventType == ProgramEvent.SYMBOL_REMOVED) { + handleSymbolRemoved(record); + } + // Handle data type changes (includes global type definitions, structures, etc.) + else if (eventType == ProgramEvent.DATA_TYPE_CHANGED) { + handleDataTypeChanged(record); + } + // Handle data type added events + else if (eventType == ProgramEvent.DATA_TYPE_ADDED) { + handleDataTypeAdded(record); + } + // Handle data type removed events + else if (eventType == ProgramEvent.DATA_TYPE_REMOVED) { + handleDataTypeRemoved(record); + } + // Handle data type renamed events + else if (eventType == ProgramEvent.DATA_TYPE_RENAMED) { + handleDataTypeRenamed(record); + } + // Handle function signature changes (parameters, return types, etc.) + else if (eventType == ProgramEvent.FUNCTION_CHANGED) { + handleFunctionSignatureChanged(record); + } + } + + private void handleSymbolRenamed(ProgramChangeRecord record) { + Object newValue = record.getNewValue(); + Object oldValue = record.getOldValue(); + + String newName = (newValue != null) ? newValue.toString() : "null"; + String oldName = (oldValue != null) ? oldValue.toString() : "null"; + + Msg.info(this, String.format("SYMBOL RENAMED: '%s' -> '%s' at address %s", + oldName, newName, record.getStart())); + + // Try to get additional information about the symbol + try { + Program program = getCurrentProgram(); + if (program != null) { + SymbolTable symbolTable = program.getSymbolTable(); + Symbol[] symbols = symbolTable.getSymbols(record.getStart()); + + for (Symbol symbol : symbols) { + if (symbol.getName().equals(newName)) { + String symbolType = getSymbolTypeDescription(symbol); + Msg.info(this, String.format(" Symbol type: %s, Namespace: %s", + symbolType, symbol.getParentNamespace().getName())); + + // If it's a function, log additional function details + if (symbol.getSymbolType() == SymbolType.FUNCTION) { + Function function = (Function) symbol.getObject(); + if (function != null) { + Msg.info(this, String.format(" Function signature: %s", + function.getPrototypeString(false, false))); + } + } + break; + } + } + } + } catch (Exception e) { + Msg.error(this, "Error getting symbol details: " + e.getMessage()); + } + } + + private void handleFunctionChanged(ProgramChangeRecord record) { + // This handles function-specific changes including renames and signature changes + Object newValue = record.getNewValue(); + Object oldValue = record.getOldValue(); + + if (newValue instanceof Function && oldValue instanceof Function) { + Function newFunc = (Function) newValue; + Function oldFunc = (Function) oldValue; + + // Check for name changes + if (!newFunc.getName().equals(oldFunc.getName())) { + Msg.info(this, String.format("FUNCTION RENAMED: '%s' -> '%s' at address %s", + oldFunc.getName(), newFunc.getName(), newFunc.getEntryPoint())); + } + + // Check for signature changes + String oldSignature = oldFunc.getPrototypeString(false, false); + String newSignature = newFunc.getPrototypeString(false, false); + if (!oldSignature.equals(newSignature)) { + Msg.info(this, String.format("FUNCTION SIGNATURE CHANGED at address %s:", newFunc.getEntryPoint())); + Msg.info(this, String.format(" Old: %s", oldSignature)); + Msg.info(this, String.format(" New: %s", newSignature)); + + // Log specific changes + logFunctionSignatureDetails(oldFunc, newFunc); + } + } else if (newValue instanceof Function) { + Function function = (Function) newValue; + Msg.info(this, String.format("FUNCTION MODIFIED: %s at address %s", + function.getName(), function.getEntryPoint())); + Msg.info(this, String.format(" Signature: %s", function.getPrototypeString(false, false))); + } + } + + private void handleFunctionSignatureChanged(ProgramChangeRecord record) { + // Handle detailed function signature changes + handleFunctionChanged(record); // Reuse the existing logic + } + + private void handleDataTypeChanged(ProgramChangeRecord record) { + Object newValue = record.getNewValue(); + Object oldValue = record.getOldValue(); + + Msg.info(this, String.format("DATA TYPE CHANGED at address %s", record.getStart())); + + if (oldValue != null && newValue != null) { + Msg.info(this, String.format(" Old type: %s", oldValue.toString())); + Msg.info(this, String.format(" New type: %s", newValue.toString())); + } else if (newValue != null) { + Msg.info(this, String.format(" Type set to: %s", newValue.toString())); + } + + // Try to get more context about the data type change + try { + Program program = getCurrentProgram(); + if (program != null && record.getStart() != null) { + ghidra.program.model.data.Data data = program.getListing().getDataAt(record.getStart()); + if (data != null) { + Msg.info(this, String.format(" Data label: %s", data.getLabel())); + Msg.info(this, String.format(" Data type: %s", data.getDataType().getName())); + } + } + } catch (Exception e) { + Msg.error(this, "Error getting data type details: " + e.getMessage()); + } + } + + private void handleDataTypeAdded(ProgramChangeRecord record) { + Object newValue = record.getNewValue(); + + Msg.info(this, String.format("DATA TYPE ADDED at address %s", record.getStart())); + if (newValue != null) { + Msg.info(this, String.format(" Type: %s", newValue.toString())); + } + } + + private void handleDataTypeRemoved(ProgramChangeRecord record) { + Object oldValue = record.getOldValue(); + + Msg.info(this, String.format("DATA TYPE REMOVED at address %s", record.getStart())); + if (oldValue != null) { + Msg.info(this, String.format(" Removed type: %s", oldValue.toString())); + } + } + + private void handleDataTypeRenamed(ProgramChangeRecord record) { + Object newValue = record.getNewValue(); + Object oldValue = record.getOldValue(); + + String newName = (newValue != null) ? newValue.toString() : "null"; + String oldName = (oldValue != null) ? oldValue.toString() : "null"; + + Msg.info(this, String.format("DATA TYPE RENAMED: '%s' -> '%s' at address %s", + oldName, newName, record.getStart())); + } + + private void logFunctionSignatureDetails(Function oldFunc, Function newFunc) { + try { + // Check return type changes + if (!oldFunc.getReturnType().equals(newFunc.getReturnType())) { + Msg.info(this, String.format(" Return type changed: %s -> %s", + oldFunc.getReturnType().getName(), newFunc.getReturnType().getName())); + } + + // Check parameter count changes + int oldParamCount = oldFunc.getParameterCount(); + int newParamCount = newFunc.getParameterCount(); + if (oldParamCount != newParamCount) { + Msg.info(this, String.format(" Parameter count changed: %d -> %d", + oldParamCount, newParamCount)); + } + + // Check individual parameter changes + int maxParams = Math.max(oldParamCount, newParamCount); + for (int i = 0; i < maxParams; i++) { + if (i < oldParamCount && i < newParamCount) { + ghidra.program.model.listing.Parameter oldParam = oldFunc.getParameter(i); + ghidra.program.model.listing.Parameter newParam = newFunc.getParameter(i); + + if (!oldParam.getDataType().equals(newParam.getDataType())) { + Msg.info(this, String.format(" Parameter %d type changed: %s -> %s", + i, oldParam.getDataType().getName(), newParam.getDataType().getName())); + } + + if (!oldParam.getName().equals(newParam.getName())) { + Msg.info(this, String.format(" Parameter %d name changed: %s -> %s", + i, oldParam.getName(), newParam.getName())); + } + } else if (i < newParamCount) { + ghidra.program.model.listing.Parameter newParam = newFunc.getParameter(i); + Msg.info(this, String.format(" Parameter %d added: %s %s", + i, newParam.getDataType().getName(), newParam.getName())); + } else { + ghidra.program.model.listing.Parameter oldParam = oldFunc.getParameter(i); + Msg.info(this, String.format(" Parameter %d removed: %s %s", + i, oldParam.getDataType().getName(), oldParam.getName())); + } + } + + // Check calling convention changes + if (!oldFunc.getCallingConventionName().equals(newFunc.getCallingConventionName())) { + Msg.info(this, String.format(" Calling convention changed: %s -> %s", + oldFunc.getCallingConventionName(), newFunc.getCallingConventionName())); + } + + } catch (Exception e) { + Msg.error(this, "Error logging function signature details: " + e.getMessage()); + } + } + + private void handleSymbolAdded(ProgramChangeRecord record) { + Object newValue = record.getNewValue(); + if (newValue instanceof Symbol) { + Symbol symbol = (Symbol) newValue; + String symbolType = getSymbolTypeDescription(symbol); + Msg.info(this, String.format("SYMBOL ADDED: '%s' (%s) at address %s", + symbol.getName(), symbolType, symbol.getAddress())); + } + } + + private void handleSymbolRemoved(ProgramChangeRecord record) { + Object oldValue = record.getOldValue(); + if (oldValue instanceof Symbol) { + Symbol symbol = (Symbol) oldValue; + String symbolType = getSymbolTypeDescription(symbol); + Msg.info(this, String.format("SYMBOL REMOVED: '%s' (%s) at address %s", + symbol.getName(), symbolType, symbol.getAddress())); + } + } + + private String getSymbolTypeDescription(Symbol symbol) { + SymbolType type = symbol.getSymbolType(); + + if (type == SymbolType.FUNCTION) { + return "Function"; + } else if (type == SymbolType.LABEL) { + return "Label"; + } else if (type == SymbolType.CLASS) { + return "Class"; + } else if (type == SymbolType.NAMESPACE) { + return "Namespace"; + } else if (type == SymbolType.PARAMETER) { + return "Parameter"; + } else if (type == SymbolType.LOCAL_VAR) { + return "Local Variable"; + } else if (type == SymbolType.GLOBAL_VAR) { + return "Global Variable"; + } else if (type == SymbolType.LIBRARY) { + return "Library"; + } else { + return type.toString(); + } + } + + @Override + protected void dispose() { + Program program = getCurrentProgram(); + if (program != null) { + program.removeListener(this); + } + super.dispose(); + Msg.info(this, "SymbolRenameLoggerPlugin disposed"); + } +} \ No newline at end of file diff --git a/GhidraPlugin/src/main/java/symbollogger/SymbolRenameLoggerPlugin.java b/GhidraPlugin/src/main/java/symbollogger/SymbolRenameLoggerPlugin.java deleted file mode 100644 index 774cd317..00000000 --- a/GhidraPlugin/src/main/java/symbollogger/SymbolRenameLoggerPlugin.java +++ /dev/null @@ -1,198 +0,0 @@ -package symbollogger; - -import ghidra.app.plugin.PluginCategoryNames; -import ghidra.app.plugin.ProgramPlugin; -import ghidra.framework.plugintool.PluginInfo; -import ghidra.framework.plugintool.PluginTool; -import ghidra.framework.plugintool.util.PluginStatus; -import ghidra.program.model.listing.Program; -import ghidra.program.util.ProgramChangeRecord; -import ghidra.program.util.ProgramEvent; -import ghidra.util.Msg; -import ghidra.framework.model.*; -import ghidra.program.model.symbol.*; -import ghidra.program.model.listing.Function; -import ghidra.program.util.*; - -@PluginInfo( - status = PluginStatus.STABLE, - packageName = "SymbolLogger", - category = PluginCategoryNames.MISC, - shortDescription = "Logs symbol and function renames", - description = "A plugin that monitors and logs all symbol and function rename events to the console", - servicesRequired = {}, - servicesProvided = {} -) -public class SymbolRenameLoggerPlugin extends ProgramPlugin implements DomainObjectListener { - - public SymbolRenameLoggerPlugin(PluginTool tool) { - super(tool); - } - - @Override - protected void init() { - super.init(); - Msg.info(this, "SymbolRenameLoggerPlugin initialized"); - } - - @Override - protected void programActivated(Program program) { - super.programActivated(program); - if (program != null) { - program.addListener(this); - Msg.info(this, "Started listening for rename events in program: " + program.getName()); - } - } - - @Override - protected void programDeactivated(Program program) { - if (program != null) { - program.removeListener(this); - Msg.info(this, "Stopped listening for rename events in program: " + program.getName()); - } - super.programDeactivated(program); - } - - @Override - public void domainObjectChanged(DomainObjectChangedEvent ev) { - for (DomainObjectChangeRecord record : ev) { - if (record instanceof ProgramChangeRecord) { - ProgramChangeRecord progRecord = (ProgramChangeRecord) record; - handleProgramChange(progRecord); - } - } - } - - private void handleProgramChange(ProgramChangeRecord record) { - ProgramEvent eventType = record.getEventType(); - - // Handle symbol rename events - if (eventType == ProgramEvent.SYMBOL_RENAMED) { - handleSymbolRenamed(record); - } - // Handle function rename events (functions are also symbols, but we can be more specific) - else if (eventType == ProgramEvent.FUNCTION_CHANGED) { - handleFunctionChanged(record); - } - // Handle symbol added events (in case we want to track new symbols) - else if (eventType == ProgramEvent.SYMBOL_ADDED) { - handleSymbolAdded(record); - } - // Handle symbol removed events - else if (eventType == ProgramEvent.SYMBOL_REMOVED) { - handleSymbolRemoved(record); - } - } - - private void handleSymbolRenamed(ProgramChangeRecord record) { - Object newValue = record.getNewValue(); - Object oldValue = record.getOldValue(); - - String newName = (newValue != null) ? newValue.toString() : "null"; - String oldName = (oldValue != null) ? oldValue.toString() : "null"; - - Msg.info(this, String.format("SYMBOL RENAMED: '%s' -> '%s' at address %s", - oldName, newName, record.getStart())); - - // Try to get additional information about the symbol - try { - Program program = getCurrentProgram(); - if (program != null) { - SymbolTable symbolTable = program.getSymbolTable(); - Symbol[] symbols = symbolTable.getSymbols(record.getStart()); - - for (Symbol symbol : symbols) { - if (symbol.getName().equals(newName)) { - String symbolType = getSymbolTypeDescription(symbol); - Msg.info(this, String.format(" Symbol type: %s, Namespace: %s", - symbolType, symbol.getParentNamespace().getName())); - - // If it's a function, log additional function details - if (symbol.getSymbolType() == SymbolType.FUNCTION) { - Function function = (Function) symbol.getObject(); - if (function != null) { - Msg.info(this, String.format(" Function signature: %s", - function.getPrototypeString(false, false))); - } - } - break; - } - } - } - } catch (Exception e) { - Msg.error(this, "Error getting symbol details: " + e.getMessage()); - } - } - - private void handleFunctionChanged(ProgramChangeRecord record) { - // This handles function-specific changes including renames - Object newValue = record.getNewValue(); - Object oldValue = record.getOldValue(); - - if (newValue instanceof Function && oldValue instanceof Function) { - Function newFunc = (Function) newValue; - Function oldFunc = (Function) oldValue; - - if (!newFunc.getName().equals(oldFunc.getName())) { - Msg.info(this, String.format("FUNCTION RENAMED: '%s' -> '%s' at address %s", - oldFunc.getName(), newFunc.getName(), newFunc.getEntryPoint())); - Msg.info(this, String.format(" Function signature: %s", - newFunc.getPrototypeString(false, false))); - } - } - } - - private void handleSymbolAdded(ProgramChangeRecord record) { - Object newValue = record.getNewValue(); - if (newValue instanceof Symbol) { - Symbol symbol = (Symbol) newValue; - String symbolType = getSymbolTypeDescription(symbol); - Msg.info(this, String.format("SYMBOL ADDED: '%s' (%s) at address %s", - symbol.getName(), symbolType, symbol.getAddress())); - } - } - - private void handleSymbolRemoved(ProgramChangeRecord record) { - Object oldValue = record.getOldValue(); - if (oldValue instanceof Symbol) { - Symbol symbol = (Symbol) oldValue; - String symbolType = getSymbolTypeDescription(symbol); - Msg.info(this, String.format("SYMBOL REMOVED: '%s' (%s) at address %s", - symbol.getName(), symbolType, symbol.getAddress())); - } - } - - private String getSymbolTypeDescription(Symbol symbol) { - SymbolType type = symbol.getSymbolType(); - switch (type) { - case FUNCTION: - return "Function"; - case LABEL: - return "Label"; - case CLASS: - return "Class"; - case NAMESPACE: - return "Namespace"; - case PARAMETER: - return "Parameter"; - case LOCAL_VAR: - return "Local Variable"; - case GLOBAL_VAR: - return "Global Variable"; - case LIBRARY: - return "Library"; - default: - return type.toString(); - } - } - - @Override - protected void dispose() { - Program program = getCurrentProgram(); - if (program != null) { - program.removeListener(this); - } - super.dispose(); - Msg.info(this, "SymbolRenameLoggerPlugin disposed"); - } -} \ No newline at end of file diff --git a/GhidraPlugin/src/main/resources/images/README.txt b/GhidraPlugin/src/main/resources/images/README.txt new file mode 100644 index 00000000..f20ae77b --- /dev/null +++ b/GhidraPlugin/src/main/resources/images/README.txt @@ -0,0 +1,2 @@ +The "src/resources/images" directory is intended to hold all image/icon files used by +this module. diff --git a/game_re/gh_fix/r3_BNK_playMovie.cxx b/game_re/gh_fix/r3_BNK_playMovie.cxx index d5c703fc..e24f3f16 100644 --- a/game_re/gh_fix/r3_BNK_playMovie.cxx +++ b/game_re/gh_fix/r3_BNK_playMovie.cxx @@ -167,7 +167,7 @@ LAB_00442549: r3_validateBinkVideoQuality(g_bink_videoBpp, g_bink_realVideoQuality); FUN_00485400(haveSoundtrack, 0); FUN_004420f0(0); - uVar7 = FUN_00401270(); + uVar7 = FUN_00401270(0, 0); FUN_0046f680(uVar7, 0); FUN_0046ed40(0, 0, 1); FUN_0046f410(0, 0xff);