From 32ce329db1e3f0030565da27cc8b0d4d220461f0 Mon Sep 17 00:00:00 2001 From: Dhruv Maroo Date: Fri, 21 Apr 2023 01:04:29 +0530 Subject: [PATCH] Add Rust decompiler widget plugin --- .../ghidrust/decompiler/RustDecPlugin.java | 99 +++++++++++++ .../ghidrust/decompiler/RustDecProvider.java | 130 ++++++++++++++++++ 2 files changed, 229 insertions(+) create mode 100644 src/main/java/ghidrust/decompiler/RustDecPlugin.java create mode 100644 src/main/java/ghidrust/decompiler/RustDecProvider.java diff --git a/src/main/java/ghidrust/decompiler/RustDecPlugin.java b/src/main/java/ghidrust/decompiler/RustDecPlugin.java new file mode 100644 index 0000000..f99cf60 --- /dev/null +++ b/src/main/java/ghidrust/decompiler/RustDecPlugin.java @@ -0,0 +1,99 @@ +/* ### + * 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 ghidrust.decompiler; + +import ghidra.app.plugin.PluginCategoryNames; +import docking.ActionContext; +import docking.action.DockingAction; +import ghidra.app.events.*; +import ghidra.framework.plugintool.Plugin; +import ghidra.framework.plugintool.PluginInfo; +import ghidra.framework.plugintool.PluginTool; +import ghidra.framework.plugintool.util.PluginStatus; +import ghidra.framework.plugintool.PluginEvent; + +import ghidra.program.model.listing.Program; +import ghidra.program.util.ProgramLocation; +import ghidra.util.Msg; +import ghidrust.analyzer.RustStdAnalyzer; +import docking.action.MenuData; + +//@formatter:off +@PluginInfo( + status = PluginStatus.RELEASED, + packageName = "HELLO", + category = PluginCategoryNames.DECOMPILER, + shortDescription = "Rust Decompiler", + description = "Decompile Rust binaries' assembly to Rust code", + eventsConsumed = { + ProgramActivatedPluginEvent.class, ProgramLocationPluginEvent.class, ProgramClosedPluginEvent.class + } +) +//@formatter:on +public class RustDecPlugin extends Plugin { + Program program; + RustDecProvider provider; + + public RustDecPlugin(PluginTool tool) { + super(tool); + provider = new RustDecProvider(this, getName(), null); + + DockingAction dec_plugin = new DockingAction("GhidRust", getName()) { + @Override + public void actionPerformed(ActionContext context) { + provider.activateProvider();; + } + }; + + dec_plugin.setEnabled(true); + dec_plugin.setMenuBarData(new MenuData(new String[] { "GhidRust", "Open decompiler" })); + + DockingAction check_plugin = new DockingAction("GhidRust", getName()) { + @Override + public void actionPerformed(ActionContext context) { + if (RustStdAnalyzer.isRustBinary(program)) { + Msg.info(this, "[+] Yes, this may be a Rust binary!"); + } else { + Msg.info(this, "[-] No, this may not be a Rust binary!"); + } + } + }; + + check_plugin.setEnabled(true); + check_plugin.setMenuBarData(new MenuData(new String[] { "GhidRust", "Check if Rust binary" })); + + tool.addAction(dec_plugin); + tool.addAction(check_plugin); + } + + @Override + public void processEvent(PluginEvent event) { + if (event instanceof ProgramActivatedPluginEvent) { + program = ((ProgramActivatedPluginEvent) event).getActiveProgram(); + provider.setProgram(program); + provider.setLocation(null); + } else if (event instanceof ProgramLocationPluginEvent) { + ProgramLocation location = ((ProgramLocationPluginEvent) event).getLocation(); + provider.setLocation(location.getAddress()); + } else if (event instanceof ProgramClosedPluginEvent) { + program = null; + provider.setProgram(program); + provider.setLocation(null); + } + + provider.reload(); + } +} diff --git a/src/main/java/ghidrust/decompiler/RustDecProvider.java b/src/main/java/ghidrust/decompiler/RustDecProvider.java new file mode 100644 index 0000000..abe4921 --- /dev/null +++ b/src/main/java/ghidrust/decompiler/RustDecProvider.java @@ -0,0 +1,130 @@ +package ghidrust.decompiler; + +import ghidra.program.model.listing.Program; +import ghidra.program.model.address.Address; +import ghidra.program.model.listing.Function; + +import ghidra.app.decompiler.DecompInterface; +import ghidra.app.decompiler.DecompileResults; + +import javax.swing.JComponent; +import javax.swing.JLabel; +import javax.swing.JPanel; +import javax.swing.JTextArea; +import javax.swing.JToolBar; +import javax.swing.JButton; +import javax.swing.Box; + +import java.awt.BorderLayout; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; + +import docking.ComponentProvider; +import ghidra.util.task.ConsoleTaskMonitor; +import resources.ResourceManager; + +public class RustDecProvider extends ComponentProvider { + private JPanel panel; + private JTextArea code_area; + private JLabel func_title; + private JToolBar toolbar; + private JButton reload; + + private Program prog; + private Address addr; + + private DecompInterface decomp_ifc = null; + + private static final String EMPTY_LABEL = ""; + + public RustDecProvider(RustDecPlugin plugin, String owner, Program p) { + super(plugin.getTool(), owner, owner); + setIcon(ResourceManager.loadImage("images/icon.png")); + + decomp_ifc = new DecompInterface(); + setProgram(p); + + buildPanel(); + } + + @Override + public JComponent getComponent() { + return panel; + } + + private void buildPanel() { + panel = new JPanel(new BorderLayout()); + + func_title = new JLabel(EMPTY_LABEL); + reload = new JButton(ResourceManager.loadImage("images/reload.png")); + + reload.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + reload(); + } + }); + + toolbar = new JToolBar("GhidRust", JToolBar.HORIZONTAL); + toolbar.add(func_title); + toolbar.add(Box.createHorizontalGlue()); + toolbar.add(reload); + + code_area = new JTextArea(); + + panel.add(toolbar, BorderLayout.PAGE_START); + panel.add(code_area); + } + + public void activateProvider() { + setVisible(true); + } + + public void setProgram(Program p) { + prog = p; + + decomp_ifc.closeProgram(); + if (prog != null) { + decomp_ifc.openProgram(prog); + } + } + + public void setLocation(Address a) { + addr = a; + } + + public void reload() { + if (prog == null) { + func_title.setText(EMPTY_LABEL); + code_area.setText("[?] Open a program to see the decompilation!\n"); + return; + } + + if (addr == null) { + func_title.setText(EMPTY_LABEL); + code_area.setText("[?] Select a memory location to decompile!\n"); + return; + } + + Function func = prog.getFunctionManager().getFunctionContaining(addr); + if (func == null) { + func_title.setText(EMPTY_LABEL); + code_area.setText("[!] No function found at " + addr.toString() + "\n"); + return; + } + + func_title.setText(func.getName()); + + if (decomp_ifc == null) { + code_area.setText("[!] Decompiler has not been initialized!\n"); + return; + } + + DecompileResults results = decomp_ifc.decompileFunction(func, 0, new ConsoleTaskMonitor()); + if (results == null || results.getDecompiledFunction() == null) { + code_area.setText("[!] Failed to decompile " + func.getName() + "\n"); + return; + } + + code_area.setText(results.getDecompiledFunction().getC()); + } +}