mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-231 update ExportImagesScript
Use currentSelection and allow user to specify output directory.
This commit is contained in:
parent
2b08598dba
commit
c41e34cbf8
7 changed files with 85 additions and 50 deletions
|
@ -13,9 +13,8 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
//Looks for defined image data in the program
|
//Looks for already defined graphic image data in the program
|
||||||
//and writes out any images to the directory
|
//and writes all selected images to a directory.
|
||||||
//where the executable is stored
|
|
||||||
//@category Images
|
//@category Images
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
@ -25,56 +24,45 @@ import java.io.IOException;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
|
||||||
import generic.util.image.ImageUtils;
|
import generic.util.image.ImageUtils;
|
||||||
import ghidra.app.script.GhidraScript;
|
import ghidra.app.script.GhidraScript;
|
||||||
import ghidra.program.model.data.*;
|
import ghidra.program.model.data.DataImage;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.data.Resource;
|
||||||
|
import ghidra.program.model.listing.Data;
|
||||||
|
import ghidra.program.util.DefinedDataIterator;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
|
||||||
public class ExportImagesScript extends GhidraScript {
|
public class ExportImagesScript extends GhidraScript {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws IOException, CancelledException {
|
||||||
Listing listing = currentProgram.getListing();
|
String programName = currentProgram.getName();
|
||||||
DataIterator dataIt = listing.getDefinedData(true);
|
File outDir = askDirectory("Select Image Save Directory", "Select");
|
||||||
while (dataIt.hasNext() && !monitor.isCancelled()) {
|
if (outDir == null || !outDir.isDirectory()) {
|
||||||
Data data = dataIt.next();
|
return;
|
||||||
String execPath = currentProgram.getExecutablePath();
|
}
|
||||||
String imagePath = execPath.substring(0, execPath.lastIndexOf(File.separator) + 1);
|
|
||||||
String execName = execPath.substring(execPath.lastIndexOf(File.separator) + 1);
|
|
||||||
String filename = imagePath + execName;
|
|
||||||
|
|
||||||
checkDataForImage(data, filename);
|
for (Data data : DefinedDataIterator.byDataType(currentProgram, currentSelection,
|
||||||
|
dt -> dt instanceof Resource)) {
|
||||||
|
Object val = data.getValue();
|
||||||
|
if (val instanceof DataImage) {
|
||||||
|
DataImage dataImg = (DataImage) val;
|
||||||
|
String imageType = dataImg.getImageFileType();
|
||||||
|
|
||||||
|
String outputName = programName + "_" + data.getLabel() + "_" +
|
||||||
|
data.getAddress().toString() + "." + imageType;
|
||||||
|
File outputFile = new File(outDir, outputName);
|
||||||
|
|
||||||
|
println("Found " + imageType + " in program " + programName + " at address " +
|
||||||
|
data.getAddressString(false, true));
|
||||||
|
writeImageToFile(data, imageType, outputFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkDataForImage(Data data, String filename) throws IOException {
|
private void writeImageToFile(Data data, String imageType, File outputFile) throws IOException {
|
||||||
DataType dataType = data.getDataType();
|
|
||||||
String imageType = null;
|
|
||||||
|
|
||||||
if (data.getMnemonicString().equals("PNG")) {
|
|
||||||
println("Found PNG in program " + currentProgram.getExecutablePath() + " at address " +
|
|
||||||
data.getAddressString(false, true));
|
|
||||||
filename += "_" + data.getLabel() + "_" + data.getAddress().toString() + ".png";
|
|
||||||
imageType = "PNG";
|
|
||||||
}
|
|
||||||
else if (data.getMnemonicString().equals("GIF")) {
|
|
||||||
println("Found GIF in program " + currentProgram.getExecutablePath() + " at address " +
|
|
||||||
data.getAddressString(false, true));
|
|
||||||
filename += "_" + data.getLabel() + "_" + data.getAddress().toString() + ".gif";
|
|
||||||
imageType = "GIF";
|
|
||||||
}
|
|
||||||
else if (dataType instanceof BitmapResourceDataType) {
|
|
||||||
println("Found BMP in program " + currentProgram.getExecutablePath() + " at address " +
|
|
||||||
data.getAddressString(false, true));
|
|
||||||
filename += "_" + data.getLabel() + "_" + data.getAddress().toString() + ".bmp";
|
|
||||||
imageType = "BMP";
|
|
||||||
}
|
|
||||||
if (imageType != null) {
|
|
||||||
writeImageToFile(data, imageType, filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeImageToFile(Data data, String imageType, String filename) throws IOException {
|
|
||||||
DataImage image = (DataImage) data.getValue();
|
DataImage image = (DataImage) data.getValue();
|
||||||
if (image == null) {
|
if (image == null) {
|
||||||
println("Found an image at " + data.getAddressString(false, true) +
|
println("Found an image at " + data.getAddressString(false, true) +
|
||||||
|
@ -83,13 +71,15 @@ public class ExportImagesScript extends GhidraScript {
|
||||||
}
|
}
|
||||||
ImageIcon icon = image.getImageIcon();
|
ImageIcon icon = image.getImageIcon();
|
||||||
BufferedImage buffy = ImageUtils.getBufferedImage(icon.getImage());
|
BufferedImage buffy = ImageUtils.getBufferedImage(icon.getImage());
|
||||||
File imageFile = new File(filename);
|
boolean didWrite = ImageIO.write(buffy, imageType, outputFile);
|
||||||
boolean didWrite = ImageIO.write(buffy, imageType, imageFile);
|
|
||||||
if (!didWrite) {
|
if (!didWrite) {
|
||||||
didWrite = ImageIO.write(buffy, "PNG", imageFile);
|
// ie. because bmp doesn't support transparency
|
||||||
|
outputFile = new File(outputFile.getParent(),
|
||||||
|
FilenameUtils.removeExtension(outputFile.getName()) + ".png");
|
||||||
|
didWrite = ImageIO.write(buffy, "PNG", outputFile);
|
||||||
}
|
}
|
||||||
if (!didWrite) {
|
if (!didWrite) {
|
||||||
imageFile.delete();
|
outputFile.delete();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -319,6 +319,11 @@ public class BitmapResource {
|
||||||
public ImageIcon getImageIcon() {
|
public ImageIcon getImageIcon() {
|
||||||
return ResourceManager.getImageIconFromImage("Bitmap Data Image", image);
|
return ResourceManager.getImageIconFromImage("Bitmap Data Image", image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getImageFileType() {
|
||||||
|
return "bmp";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -16,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.program.model.data;
|
package ghidra.program.model.data;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import javax.swing.ImageIcon;
|
import javax.swing.ImageIcon;
|
||||||
|
|
||||||
public abstract class DataImage {
|
public abstract class DataImage {
|
||||||
|
@ -28,6 +28,15 @@ public abstract class DataImage {
|
||||||
*/
|
*/
|
||||||
public abstract ImageIcon getImageIcon();
|
public abstract ImageIcon getImageIcon();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the type of the underlying image data, suitable for
|
||||||
|
* {@link ImageIO#write(java.awt.image.RenderedImage, String, java.io.File)}'s formatName
|
||||||
|
* parameter.
|
||||||
|
*
|
||||||
|
* @return String image format type, ie. "png", "gif", "bmp"
|
||||||
|
*/
|
||||||
|
public abstract String getImageFileType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set string description (returned by toString)
|
* Set string description (returned by toString)
|
||||||
* @param description
|
* @param description
|
||||||
|
|
|
@ -109,6 +109,11 @@ public class GifDataType extends BuiltIn implements Dynamic, Resource {
|
||||||
public ImageIcon getImageIcon() {
|
public ImageIcon getImageIcon() {
|
||||||
return new ImageIcon(data, "<GIF-Image>");
|
return new ImageIcon(data, "<GIF-Image>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getImageFileType() {
|
||||||
|
return "gif";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -123,6 +123,11 @@ public class JPEGDataType extends BuiltIn implements Dynamic, Resource {
|
||||||
public ImageIcon getImageIcon() {
|
public ImageIcon getImageIcon() {
|
||||||
return new ImageIcon(data, "<JPEG-Image>");
|
return new ImageIcon(data, "<JPEG-Image>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getImageFileType() {
|
||||||
|
return "jpg";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -105,6 +105,11 @@ public class PngDataType extends BuiltIn implements Dynamic, Resource {
|
||||||
public ImageIcon getImageIcon() {
|
public ImageIcon getImageIcon() {
|
||||||
return new ImageIcon(data, "<PNG-Image>");
|
return new ImageIcon(data, "<PNG-Image>");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getImageFileType() {
|
||||||
|
return "png";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -44,6 +44,20 @@ public class DefinedDataIterator implements DataIterator {
|
||||||
return new DefinedDataIterator(program, null, dataTypePredicate, null);
|
return new DefinedDataIterator(program, null, dataTypePredicate, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new iterator that traverses a portion of the Program's address space, returning
|
||||||
|
* data instances that successfully match the predicate.
|
||||||
|
*
|
||||||
|
* @param program Program to search
|
||||||
|
* @param addresses addresses to limit the iteration to
|
||||||
|
* @param dataTypePredicate {@link Predicate} that tests each data instance's {@link DataType}
|
||||||
|
* @return new iterator
|
||||||
|
*/
|
||||||
|
public static DefinedDataIterator byDataType(Program program, AddressSetView addresses,
|
||||||
|
Predicate<DataType> dataTypePredicate) {
|
||||||
|
return new DefinedDataIterator(program, addresses, dataTypePredicate, null);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new iterator that traverses the entire Program's address space, returning
|
* Creates a new iterator that traverses the entire Program's address space, returning
|
||||||
* data instances that successfully match the predicate.
|
* data instances that successfully match the predicate.
|
||||||
|
@ -113,8 +127,10 @@ public class DefinedDataIterator implements DataIterator {
|
||||||
this.dataTypePredicate = dataTypePredicate;
|
this.dataTypePredicate = dataTypePredicate;
|
||||||
this.dataInstancePredicate = dataInstancePredicate;
|
this.dataInstancePredicate = dataInstancePredicate;
|
||||||
|
|
||||||
itStack.addLast(program.getListing().getDefinedData(
|
itStack.addLast(program.getListing()
|
||||||
(addrs == null) ? program.getMemory().getAllInitializedAddressSet() : addrs, true));
|
.getDefinedData(
|
||||||
|
(addrs == null) ? program.getMemory().getAllInitializedAddressSet() : addrs,
|
||||||
|
true));
|
||||||
}
|
}
|
||||||
|
|
||||||
private DefinedDataIterator(Data singleDataInstance, Predicate<DataType> dataTypePredicate,
|
private DefinedDataIterator(Data singleDataInstance, Predicate<DataType> dataTypePredicate,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue