GP-231 update ExportImagesScript

Use currentSelection and allow user to specify output directory.
This commit is contained in:
dev747368 2020-10-06 21:10:16 -04:00
parent 2b08598dba
commit c41e34cbf8
7 changed files with 85 additions and 50 deletions

View file

@ -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);
}
} }
private void checkDataForImage(Data data, String filename) throws IOException { for (Data data : DefinedDataIterator.byDataType(currentProgram, currentSelection,
DataType dataType = data.getDataType(); dt -> dt instanceof Resource)) {
String imageType = null; Object val = data.getValue();
if (val instanceof DataImage) {
DataImage dataImg = (DataImage) val;
String imageType = dataImg.getImageFileType();
if (data.getMnemonicString().equals("PNG")) { String outputName = programName + "_" + data.getLabel() + "_" +
println("Found PNG in program " + currentProgram.getExecutablePath() + " at address " + data.getAddress().toString() + "." + imageType;
File outputFile = new File(outDir, outputName);
println("Found " + imageType + " in program " + programName + " at address " +
data.getAddressString(false, true)); data.getAddressString(false, true));
filename += "_" + data.getLabel() + "_" + data.getAddress().toString() + ".png"; writeImageToFile(data, imageType, outputFile);
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 { private void writeImageToFile(Data data, String imageType, File outputFile) 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();
} }
} }
} }

View file

@ -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";
}
} }
/** /**

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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,