mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
308 lines
11 KiB
Java
308 lines
11 KiB
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.
|
|
*/
|
|
package help.screenshot;
|
|
|
|
import java.awt.*;
|
|
import java.awt.image.BufferedImage;
|
|
import java.io.File;
|
|
import java.io.IOException;
|
|
|
|
import javax.swing.*;
|
|
|
|
import org.junit.Test;
|
|
|
|
import generic.theme.GThemeDefaults.Colors;
|
|
import generic.theme.GThemeDefaults.Colors.Palette;
|
|
import ghidra.app.plugin.core.codebrowser.CodeViewerProvider;
|
|
import ghidra.app.plugin.core.references.*;
|
|
import ghidra.app.util.importer.*;
|
|
import ghidra.app.util.opinion.LoadResults;
|
|
import ghidra.app.util.opinion.LoaderService;
|
|
import ghidra.framework.main.DataTreeDialog;
|
|
import ghidra.framework.model.Project;
|
|
import ghidra.program.model.listing.CodeUnit;
|
|
import ghidra.program.model.listing.Program;
|
|
import ghidra.program.model.mem.Memory;
|
|
import ghidra.program.model.mem.MemoryAccessException;
|
|
import ghidra.util.InvalidNameException;
|
|
import ghidra.util.exception.*;
|
|
import ghidra.util.task.TaskMonitor;
|
|
|
|
public class ReferencesPluginScreenShots extends GhidraScreenShotGenerator {
|
|
|
|
public ReferencesPluginScreenShots() {
|
|
super();
|
|
}
|
|
|
|
@Test
|
|
public void testAddReferenceDialog() {
|
|
goToListing(0x401008);
|
|
performAction("Add Reference From", "ReferencesPlugin", false);
|
|
captureDialog();
|
|
}
|
|
|
|
@Test
|
|
public void testChoose_external_prog() throws Exception {
|
|
importFile(getTestDataFile("pe/w7sp1/user32.dll"));
|
|
importFile(getTestDataFile("pe/w7sp1/shlwapi.dll"));
|
|
|
|
runSwing(() -> {
|
|
DataTreeDialog dialog = new DataTreeDialog(tool.getToolFrame(),
|
|
"Choose External Program (" + "Kernel32.dll" + ")", DataTreeDialog.OPEN);
|
|
tool.showDialog(dialog);
|
|
}, false);
|
|
captureDialog();
|
|
}
|
|
|
|
@Test
|
|
public void testCreateOffsetTable() {
|
|
goToListing(0x400fd0);
|
|
makeSelection(0x400fd0, 0x400fd8);
|
|
performAction("Create Offset References", "OffsetTablePlugin", false);
|
|
JDialog d = waitForJDialog("Create Offset References");
|
|
captureDialog();
|
|
pressButtonByText(d, "Cancel");
|
|
}
|
|
|
|
@Test
|
|
public void testDropZones() {
|
|
goToListing(0x4010ae);
|
|
|
|
performAction("View/Edit References From", "ReferencesPlugin", false);
|
|
EditReferencesProvider provider = getProvider(EditReferencesProvider.class);
|
|
captureIsolatedProvider(provider, 700, 300);
|
|
captureProvider(provider);
|
|
int topMargin = 60;
|
|
int leftMargin = 10;
|
|
padImage(Colors.BACKGROUND, topMargin, leftMargin, 10, 10);
|
|
JComponent rootComp = getDockableComponent(EditReferencesProvider.class);
|
|
JComponent comp =
|
|
(JComponent) findComponentByName(provider.getComponent(), "operandLabels[0]");
|
|
Point origin = new Point(leftMargin, topMargin);
|
|
explainComponent(rootComp, comp, Palette.GREEN, origin, new Point(250, 20),
|
|
"Operand-specific Drop Zones");
|
|
comp = (JComponent) findComponentByName(provider.getComponent(), "mnemonicLabel");
|
|
explainComponent(rootComp, comp, Palette.GREEN, origin, new Point(250, 20),
|
|
"Operand-specific Drop Zones");
|
|
|
|
comp = (JComponent) findComponentByName(provider.getComponent(), "RefsTable");
|
|
explainComponent(rootComp, comp, Palette.GREEN, origin, new Point(450, 40),
|
|
"Active-operand Drop Zones");
|
|
|
|
}
|
|
|
|
private void explainComponent(JComponent rootComp, JComponent comp, Color color, Point origin,
|
|
Point point, String text) {
|
|
Rectangle bounds = getBounds(comp);
|
|
Rectangle converted = SwingUtilities.convertRectangle(comp.getParent(), bounds, rootComp);
|
|
converted.x += origin.x;
|
|
converted.y += origin.y;
|
|
drawRectangle(color, converted, 2);
|
|
Point startLine = new Point(converted.x + converted.width / 2, converted.y);
|
|
drawLine(color, 2, startLine, point);
|
|
Point p2 = new Point(point.x + 20, point.y);
|
|
drawLine(color, 2, point, p2);
|
|
Point p3 = new Point(p2.x + 4, p2.y + 5);
|
|
drawText(text, Colors.FOREGROUND, p3, 12f);
|
|
}
|
|
|
|
@Test
|
|
public void testExternal_names_dialog() {
|
|
showProvider(ExternalReferencesProvider.class);
|
|
captureProvider(ExternalReferencesProvider.class);
|
|
}
|
|
|
|
@Test
|
|
public void testExtRefPanel() {
|
|
goToListing(0x0401008);
|
|
|
|
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x401008));
|
|
ReferencesPlugin plugin = getPlugin(tool, ReferencesPlugin.class);
|
|
final EditReferenceDialog dialog = new EditReferenceDialog(plugin);
|
|
dialog.initDialog(cu, 0, 0, null);
|
|
runSwing(() -> {
|
|
JRadioButton choiceButton = (JRadioButton) getInstanceField("extRefChoice", dialog);
|
|
invokeInstanceMethod("refChoiceActivated", dialog,
|
|
new Class<?>[] { JRadioButton.class }, new Object[] { choiceButton });
|
|
}, true);
|
|
showDialogWithoutBlocking(tool, dialog);
|
|
|
|
JPanel panel = (JPanel) getInstanceField("extRefPanel", dialog);
|
|
Rectangle bounds = panel.getBounds();
|
|
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
|
|
captureDialog();
|
|
takeSnippet(bounds);
|
|
}
|
|
|
|
@Test
|
|
public void testOffsetRefsExample() throws MemoryAccessException { // gif
|
|
removeFlowArrows();
|
|
goToListing(0x0400280);
|
|
int id = program.startTransaction("Test");
|
|
Memory memory = program.getMemory();
|
|
memory.setByte(addr(0x400284), (byte) 0x14);
|
|
memory.setByte(addr(0x400288), (byte) 0x18);
|
|
memory.setByte(addr(0x40028c), (byte) 0x1c);
|
|
memory.setByte(addr(0x400290), (byte) 0x20);
|
|
program.endTransaction(id, true);
|
|
makeSelection(0x400284, 0x400293);
|
|
|
|
performAction("Create Offset References", "OffsetTablePlugin", false);
|
|
runSwing(() -> {
|
|
OffsetTableDialog dialog = (OffsetTableDialog) getDialog();
|
|
dialog.setBaseAddress(addr(0x4f5000));
|
|
});
|
|
pressOkOnDialog();
|
|
captureIsolatedProvider(CodeViewerProvider.class, 800, 600);
|
|
}
|
|
|
|
@Test
|
|
public void testRefProvider() {
|
|
goToListing(0x402355);
|
|
performAction("View/Edit References From", "ReferencesPlugin", false);
|
|
EditReferencesProvider provider = getProvider(EditReferencesProvider.class);
|
|
captureIsolatedProvider(provider, 700, 400);
|
|
}
|
|
|
|
@Test
|
|
public void testRegRefPanel() {
|
|
goToListing(0x0401008);
|
|
|
|
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x401008));
|
|
ReferencesPlugin plugin = getPlugin(tool, ReferencesPlugin.class);
|
|
final EditReferenceDialog dialog = new EditReferenceDialog(plugin);
|
|
dialog.initDialog(cu, 0, 0, null);
|
|
runSwing(() -> {
|
|
JRadioButton choiceButton = (JRadioButton) getInstanceField("regRefChoice", dialog);
|
|
invokeInstanceMethod("refChoiceActivated", dialog,
|
|
new Class<?>[] { JRadioButton.class }, new Object[] { choiceButton });
|
|
}, true);
|
|
showDialogWithoutBlocking(tool, dialog);
|
|
|
|
JPanel panel = (JPanel) getInstanceField("regRefPanel", dialog);
|
|
Rectangle bounds = panel.getBounds();
|
|
bounds.height = bounds.height / 2;
|
|
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
|
|
captureDialog();
|
|
takeSnippet(bounds);
|
|
}
|
|
|
|
@Test
|
|
public void testStackRefPanel() {
|
|
goToListing(0x0401008);
|
|
|
|
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x401008));
|
|
ReferencesPlugin plugin = getPlugin(tool, ReferencesPlugin.class);
|
|
final EditReferenceDialog dialog = new EditReferenceDialog(plugin);
|
|
dialog.initDialog(cu, 0, 0, null);
|
|
runSwing(() -> {
|
|
JRadioButton choiceButton = (JRadioButton) getInstanceField("stackRefChoice", dialog);
|
|
invokeInstanceMethod("refChoiceActivated", dialog,
|
|
new Class<?>[] { JRadioButton.class }, new Object[] { choiceButton });
|
|
}, true);
|
|
showDialogWithoutBlocking(tool, dialog);
|
|
|
|
JPanel panel = (JPanel) getInstanceField("stackRefPanel", dialog);
|
|
Rectangle bounds = panel.getBounds();
|
|
bounds.height = bounds.height / 2;
|
|
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
|
|
captureDialog();
|
|
takeSnippet(bounds);
|
|
}
|
|
|
|
@Test
|
|
public void testMemRefPanel() {
|
|
goToListing(0x0401008);
|
|
|
|
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x401008));
|
|
ReferencesPlugin plugin = getPlugin(tool, ReferencesPlugin.class);
|
|
final EditReferenceDialog dialog = new EditReferenceDialog(plugin);
|
|
dialog.initDialog(cu, 0, 0, null);
|
|
runSwing(() -> {
|
|
JRadioButton choiceButton = (JRadioButton) getInstanceField("memRefChoice", dialog);
|
|
invokeInstanceMethod("refChoiceActivated", dialog,
|
|
new Class<?>[] { JRadioButton.class }, new Object[] { choiceButton });
|
|
}, true);
|
|
showDialogWithoutBlocking(tool, dialog);
|
|
|
|
final JPanel panel = (JPanel) getInstanceField("memRefPanel", dialog);
|
|
JButton button = (JButton) getInstanceField("addrHistoryButton", panel);
|
|
Rectangle buttonBounds = button.getBounds();
|
|
buttonBounds = SwingUtilities.convertRectangle(button.getParent(), buttonBounds, panel);
|
|
buttonBounds.x += 20; // padding added by takeSnippet
|
|
buttonBounds.y += buttonBounds.height / 2 + 20; // half button height + padding added by takeSnippet()
|
|
System.out.println("Button bounds = " + buttonBounds);
|
|
Rectangle bounds = panel.getBounds();
|
|
bounds.height = 3 * bounds.height / 5; // get rid of empty space
|
|
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
|
|
captureDialog();
|
|
takeSnippet(bounds);
|
|
Image image1 = image;
|
|
|
|
runSwing(() -> {
|
|
JCheckBox checkbox = (JCheckBox) getInstanceField("offsetCheckbox", panel);
|
|
checkbox.setSelected(true);
|
|
});
|
|
bounds = panel.getBounds();
|
|
bounds.height = 3 * bounds.height / 5;
|
|
bounds = SwingUtilities.convertRectangle(panel.getParent(), bounds, null);
|
|
captureDialog();
|
|
takeSnippet(bounds);
|
|
|
|
Image image2 = image;
|
|
int gap = 40;
|
|
int width = image1.getWidth(null);
|
|
int height = image1.getHeight(null);
|
|
BufferedImage newImage = createEmptyImage(width, 2 * height + gap);
|
|
|
|
Graphics2D g2 = (Graphics2D) newImage.getGraphics();
|
|
g2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
|
|
RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
|
|
g2.drawImage(image1, 0, 0, null);
|
|
g2.drawImage(image2, 0, height + gap, null);
|
|
g2.setColor(Colors.FOREGROUND);
|
|
String label = "Address History";
|
|
int x = 150;
|
|
int y = height + gap / 2;
|
|
g2.drawString(label, x, y);
|
|
x += g2.getFontMetrics().stringWidth(label) + 5;
|
|
y -= g2.getFontMetrics().getAscent() / 3;
|
|
g2.drawLine(x, y, x + 10, y);
|
|
x += 10;
|
|
g2.drawLine(buttonBounds.x, buttonBounds.y, x, y);
|
|
g2.drawLine(buttonBounds.x, buttonBounds.y + height + gap, x, y);
|
|
image = newImage;
|
|
|
|
}
|
|
|
|
private void importFile(File file) throws CancelledException, DuplicateNameException,
|
|
InvalidNameException, VersionException, IOException {
|
|
String programNameOverride = null;
|
|
Project project = env.getProject();
|
|
LoadResults<Program> loadResults = AutoImporter.importFresh(file, project,
|
|
project.getProjectData().getRootFolder().getPathname(), this, new MessageLog(),
|
|
TaskMonitor.DUMMY, LoaderService.ACCEPT_ALL, LoadSpecChooser.CHOOSE_THE_FIRST_PREFERRED,
|
|
programNameOverride, OptionChooser.DEFAULT_OPTIONS);
|
|
|
|
try {
|
|
loadResults.getPrimary().save(project, new MessageLog(), TaskMonitor.DUMMY);
|
|
}
|
|
finally {
|
|
loadResults.release(this);
|
|
}
|
|
}
|
|
|
|
}
|