Created
October 14, 2020 08:51
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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