Skip to content

Instantly share code, notes, and snippets.

@modeco80
Created October 14, 2020 08:51
Show Gist options
  • Save modeco80/abac7907a7045f0b27a1922f4a0d2f83 to your computer and use it in GitHub Desktop.
Save modeco80/abac7907a7045f0b27a1922f4a0d2f83 to your computer and use it in GitHub Desktop.
Ghidra script to load in function symbols of Link32/Visual C++ .map files
// Ghidra script to load in symbols of Link32/Visual C++ .map files
// aiding reverse-engineering of Windows/XBOX executables with
// said map files somehow available. Maybe this could be made better?
//@author Lily
//@category Lily.Tools
import java.io.*;
import java.util.*;
import ghidra.app.script.GhidraScript;
import ghidra.program.model.symbol.*;
import ghidra.program.model.address.*;
import ghidra.program.model.mem.*;
import ghidra.program.model.listing.*;
import ghidra.program.flatapi.FlatProgramAPI;
public class VSMapLoader extends GhidraScript {
// map entry
public class MapEntry {
// The code segment we are in.
MemoryBlock cs;
// The address of the function relative to CS start.
Address address;
// The name to override Ghidra's name with.
String name;
}
// we cache here for speedy nyoomiation
// probably doesn't matter cause java is a slow piece of shit language
// but gotta make it go a little bit faster somehow
private Vector<MapEntry> mapFileParsedEntries;
private Vector<Function> allFunctions;
private void InitalizeFunctions() {
allFunctions = new Vector<Function>();
Function f = getFirstFunction();
while(f != null) {
allFunctions.add(f);
f = getFunctionAfter(f);
}
}
// The VS map format is
// 0002:00179b70 _FILESYS_init 008a2870 f realfilea:filesys.obj
// csid:raddress function_name addr2 f <libfile:>objfile
// ^ ^ ^
// we care about these only
private void ParseMap(File file) throws IOException {
mapFileParsedEntries = new Vector<MapEntry>();
FileReader reader = new FileReader(file);
BufferedReader breader = new BufferedReader(reader);
String line;
// first skip until the Address marking
// if this fails, then the file probably wasn't a map file
while((line = breader.readLine()) != null) {
if(line.startsWith(" Address"))
break;
}
breader.readLine(); // then another to avoid the empty line
while((line = breader.readLine()) != null) {
line = line.trim();
line = line.replaceAll("\\s+", " ");
String[] stuff = line.split(" ");
// break out if we're about to parse the "entry point"
if(stuff[0] == "entry")
break;
// at least 2 elements
if(stuff.length < 2)
break;
// [0] == CS
// [1] == Address (Relative to CS start)
String[] addrPair = stuff[0].split(":");
String funcName = stuff[1];
MapEntry me = new MapEntry();
me.cs = getCodeSegment(Integer.parseInt(addrPair[0], 16));
me.address = getAddress(Long.parseLong(addrPair[1], 16));
me.name = funcName;
mapFileParsedEntries.add(me);
}
}
private Address getAddress(long offset) {
return currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(offset);
}
// this allows us to directly use the code-segment ID
// from the map file
private MemoryBlock getCodeSegment(int index) {
MemoryBlock[] blocks = getMemoryBlocks();
return blocks[index];
}
public void run() throws Exception {
InitalizeFunctions();
File file = askFile("Please provide a Visual C++ .MAP file", "OK");
ParseMap(file);
FunctionManager functionMgr = currentProgram.getFunctionManager();
for(MapEntry mapEntry : mapFileParsedEntries) {
// Ghidra stores its function addresses
// already in the proper code segments,
// so we need to do that with our map entries.
Address adjusted = mapEntry.cs.getStart().add(mapEntry.address.getOffset());
Function func = functionMgr.getFunctionAt(adjusted);
if(func != null) {
String oldName = func.getName();
println(String.format("Map file %1s (at %2s) matches %3s", mapEntry.name, mapEntry.address , oldName));
func.setName(mapEntry.name, SourceType.ANALYSIS);
println(String.format("Adjusted %1s to %2s!", oldName, mapEntry.name));
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment