Skip to content

Instantly share code, notes, and snippets.

@samunders-core
Created January 4, 2021 22:20
Show Gist options
  • Save samunders-core/278ff7f7298811d962dfed57cfd44393 to your computer and use it in GitHub Desktop.
Save samunders-core/278ff7f7298811d962dfed57cfd44393 to your computer and use it in GitHub Desktop.
Ghidra script - add .so files to memory of main executable based on /proc/self/maps offsets. Assumes .so files are already in Ghidra project
//setup memory map from /proc/self/maps
//@author sam_
//@category
//@keybinding
//@menupath
//@toolbar
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import ghidra.app.script.GhidraScript;
import ghidra.app.util.HexLong;
import ghidra.app.util.Option;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.BinaryLoader;
import ghidra.app.util.opinion.LoadSpec;
import ghidra.app.util.opinion.Loader;
import ghidra.formats.gfilesystem.FileSystemService;
import ghidra.formats.gfilesystem.GFile;
import ghidra.framework.model.DomainFile;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.model.Project;
import ghidra.framework.model.ProjectData;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressFactory;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.Msg;
import ghidra.util.exception.CancelledException;
public class SharedLibrariesMemoryMap extends GhidraScript {
@Override
protected void run() throws Exception {
File f = askFile("Import contents of /proc/$(pgrep " + currentProgram.getName() + ")/maps", "Select map file");
if (f != null) {
try (InputStream in = new FileInputStream(f); InputStreamReader isr = new InputStreamReader(in); BufferedReader br = new BufferedReader(isr)) {
Loader l = new BinaryLoader();
MessageLog log = new MessageLog();
Project project = state.getProject();
ProjectData projectData = project.getProjectData();
DomainFolder rootFolder = projectData.getRootFolder();
for (String line = br.readLine(); line != null && !monitor.isCancelled(); line = br.readLine()) {
parseLine(line, rootFolder, currentProgram.getAddressFactory(), FileSystemService.getInstance(), l, log);
}
}
}
}
private void parseLine(String line, DomainFolder rootFolder, AddressFactory af, FileSystemService fss, Loader l, MessageLog log) {
String[] parts = line.split("\\s+", 4); // 93c7c000-93c88000 r-xp 00000000 fd:600 5909 /lib/libstdc++.so.6.0.20
int lastSlash = parts[parts.length - 1].lastIndexOf('/');
DomainFile df = lastSlash >= 0 ? rootFolder.getFile(parts[parts.length - 1].substring(lastSlash + 1)) : null;
GFile gf = df != null ? fss.getLocalGFile(new File(df.getMetadata().getOrDefault("Executable Location", df.getPathname()))) : null;
if (gf != null && gf.getName().matches("^.+[.]so\\b.*$") && parts.length >= 4) {
try (ByteProvider bp = fss.getByteProvider(gf.getFSRL(), monitor)) {
// 47740000-477dd000 r-xp 00000000 fd:00 179 /lib/libstdc++.so.6.0.20
// 477dd000-477ed000 ---p 0009d000 fd:00 179 /lib/libstdc++.so.6.0.20
// 477ed000-477f0000 r--p 0009d000 fd:00 179 /lib/libstdc++.so.6.0.20
// 477f0000-477f2000 rw-p 000a0000 fd:00 179 /lib/libstdc++.so.6.0.20
Collection<LoadSpec> specs = l.findSupportedLoadSpecs(bp);
Address start = af.getAddress("0x" + parts[0].replaceFirst("-.*$", "")), end = af.getAddress("0x" + parts[0].replaceFirst("^.*-", ""));
long offset = Long.decode("0x" + parts[2]);
boolean r = parts[1].matches("^[-r].*$"), w = parts[1].length() > 1 && 'w' == parts[1].charAt(1), x = parts[1].length() > 2 && 'x' == parts[1].charAt(2);
if (!addToProgram(bp, specs, start, end, offset, r, w, x, log)) {
Msg.warn(getClass(), "Failed to add to program: " + line);
}
} catch (CancelledException abort) {
} catch (Exception e) {
Msg.error(getClass(), line, e);
}
} else if (line.matches("^.+[.]so\\b.*$")) {
println("gf=" + gf + ", #parts=" + parts.length + ", path=" + (df != null ? df.getMetadata().get("Executable Location") : null) + " => skipping " + line);
}
}
private String f(boolean value, String f) {
return value ? f : "-";
}
private boolean addToProgram(ByteProvider bp, Collection<LoadSpec> specs, Address start, Address end, long offset, boolean r, boolean w, boolean x, MessageLog log) throws CancelledException, IOException {
String off = String.format("0x%08x", offset), prefix = bp.getName() + "@" + off + ".";
int instance = 0;
for (MemoryBlock block = currentProgram.getMemory().getBlock(prefix + instance); block != null; block = currentProgram.getMemory().getBlock(prefix + instance)) {
++instance;
}
Collection<Option> opts = Arrays.asList(
new Option(BinaryLoader.OPTION_NAME_BLOCK_NAME, prefix + instance, String.class, Loader.COMMAND_LINE_ARG_PREFIX + "-blockName"),
new Option(BinaryLoader.OPTION_NAME_BASE_ADDR, start, Address.class, Loader.COMMAND_LINE_ARG_PREFIX + "-baseAddr"),
new Option(BinaryLoader.OPTION_NAME_LEN, new HexLong(end.subtract(start)), HexLong.class, Loader.COMMAND_LINE_ARG_PREFIX + "-length"),
new Option(BinaryLoader.OPTION_NAME_FILE_OFFSET, new HexLong(offset), HexLong.class, Loader.COMMAND_LINE_ARG_PREFIX + "-fileOffset")
);
Msg.debug(getClass(), "Mapping " + bp.getName() + " offset " + off + " at " + start + ", flags " + f(r, "r") + f(w, "w") + f(x, "x"));
for (LoadSpec loadSpec : specs) {
List<Option> options = loadSpec.getLoader().getDefaultOptions(bp, loadSpec, null, true);
options.removeIf((opt) -> opts.stream().anyMatch((o) -> o.getName().equals(opt.getName())));
options.addAll(opts); // ghidra.plugin.importer.ImporterUtilities.addContentToProgram(PluginTool, Program, FSRL, LoadSpec, List<Option>, TaskMonitor) but without summary dialog
if (loadSpec.getLoader().loadInto(bp, loadSpec, options, log, currentProgram, monitor)) {
MemoryBlock block = currentProgram.getMemory().getBlock(prefix + instance);
block.setRead(r);
block.setWrite(w);
block.setExecute(x);
return true;
}
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment