import ghidra.app.script.GhidraScript; import ghidra.program.model.symbol.SymbolTable; import ghidra.program.model.symbol.SourceType; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.FunctionManager; import ghidra.program.model.symbol.Namespace; import ghidra.program.model.symbol.Symbol; import ghidra.program.model.mem.MemoryBlock; import java.util.*; public class ImportRtti extends GhidraScript { @Override public void run() throws Exception { // map: vftable vendor address -> (class name, [func ptrs]) (decimal-addrs form from dump) // encoded compactly: name|col|vf|func0,func1,... (up to 48) String[] data = { "Soothe2AudioProcessor|0x182506ca0|0x1824abf60|0x1813658a0,0x18052c7e0,0x18053846c,0x182504fa0,0x180536f70,0x180536f70,0x180537160,0x180536f60,0x18048db00,0x180481210,0x182505208,0x180536670,0x180536670,0x1804714b0,0x180536660,0x18048db00,0x180481210,0x1825068b0,0x180536cc0,0x180536cc0,0x180537720,0x180536cb0,0x18048db00,0x180481210,0x182504e40,0x180528ba0,0x1804714b0,0x1804714b0,0x1825067d0,0x180536b90,0x180536b90,0x180537930,0x180536b80,0x18048dc80,0x180481210,0x182505680,0x180536c60", "$SpectralProcessor@M$07$01|0x1825033e0|0x1824abb90|0x18052d390,0x18052cfb0,0x180529550,0x1804714b0,0x180529610,0x18113285a,0x1805295c0,0x180529590,0x180536b60,0x180536b60,0x1805379a0,0x18250e798,0x1804d8db0,0x1804d8db0,0x18250e3f8,0x18052c7b0,0x1804d8db0,0x1804d8db0,0x1825074f0,0x1804714b0,0x18113285a,0x1804714b0,0x1825060e0,0x18113285a,0x18113285a,0x1804d8db0,0x18053fbf0,0x1804d8db0,0x1804d8db0", "$Soothe2ModuleBase@M$01|0x1825038b0|0x1824ac7a8|0x18052fd40,0x18052cfb0,0x180529550,0x1804714b0,0x18052ce00,0x1804714b0,0x18052cb90,0x18052cbc0,0x180536b60,0x182507120,0x1805367a0,0x18052e540,0x18052ce00,0x18052cbe0,0x18048db00,0x180481210,0x18052ff40,0x180530060,0x18052cfb0", "$AudioProcessingModule@M$01|0x182503180|0x1824ac638|0x18052d580,0x18052cfb0,0x18052cfa0,0x1804714b0,0x18113285a,0x18113285a,0x18052cbe0,0x180536b60,0x180536b60,0x1825071e8,0x18052cfa0,0x18052cfb0,0x18052cfb0", "$Soothe2Module@M$01|0x182504e00|0x1824ac210|0x180535ed0,0x18052cfb0,0x180529550,0x1804714b0,0x18052b940,0x180529c60,0x18052bac0,0x18052b9d0,0x18052ba40,0x18052bad0,0x18052d3a0,0x18052b960,0x18052cb90,0x18052cbc0", "$IIRFilterExtended@M$01|0x182503a58|0x1824ac5d8|0x1805346b0,0x18052cfb0,0x18052cfa0,0x18052fb50,0x18052fb30,0x182506a00,0x18052f820,0x18048db00,0x180481210,0x18052f7d0,0x18052f7c0,0x18052fc70,0x18052f950,0x18053fc00,0x18053fbc0,0x18053fa10", "$DigitalFilter@M$0BA$01|0x182519b70|0x1824be7a0|0x18058d2b0,0x18052cfb0,0x18052cfa0,0x1804714b0,0x18113285a,0x18113285a,0x18058c850,0x18058c8b0,0x18058c7b0", "$LowPassFilter@M$0BA$01|0x18251a141|0x1824be990|0x18058d230,0x18052cfb0,0x18052cfa0,0x18058c850,0x18058c8b0,0x18058c7b0", "Soothe2FilterGraph|0x182518870|0x1824be810|0x180589260,0x18134bc00,0x18058b4d0,0x18058b380,0x18134bbd0,0x18134bbc0,0x18058b2d0,0x18058b290", "$FilterGraph@M$05$0CAA@|0x1825189b8|0x1824be228|0x18058eb1c,0x18058b010,0x18251ab48,0x18058eab0,0x18160b000,0x1804714b0,0x18058ea70,0x18058ea90,0x18058dfa0,0x18058dfc0,0x18058df40,0x18058df60,0x18058dac0,0x18058daa0", "Soothe2ModuleDecryptor|0x182504928|0x1824abe68|0x18052d520,0x1813e2a60,0x182505230,0x180536a50,0x180536a50,0x180537680,0x180536a50,0x180536a50,0x180537680", "$ModuleDecryptor@VSoothe2_DynamicCryptoManager@eden@pace|0x1825043d8|0x1824ab228|0x18052d520,0x18113285a,0x182505008,0x180538490,0x18135c520,0x182506e60,0x180536900,0x180536b60", }; SymbolTable st = currentProgram.getSymbolTable(); FunctionManager fm = currentProgram.getFunctionManager(); long base = 0x180000000L; int lab = 0; int fn = 0; for (String line : data) { String[] parts = line.split("\\|"); if (parts.length < 4) continue; String cls = parts[0]; long col = Long.decode("0x" + parts[2]); // skip vf slot - parts[2] is vftable long vf = Long.decode("0x" + parts[2]); String[] fptr = parts[3].split(","); // namespace = class name Namespace ns = st.getNamespace(cls, currentProgram.getGlobalNamespace()); if (ns == null) { Address aCol = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(col); ns = st.createClass(null, cls, aCol, SourceType.USER_DEFINED); lab++; } for (String fs : fptr) { long f = Long.decode("0x" + fs); Address addr = currentProgram.getAddressFactory().getDefaultAddressSpace().getAddress(f); Function existing = fm.getFunctionAt(addr); if (existing == null) { fm.createFunction(null, addr, null, SourceType.USER_DEFINED); fn++; } String nm = cls + "_v" + fptr.length + ""; Function fx = fm.getFunctionAt(addr); if (fx != null && fx.getSymbol() != null && fx.getSymbol().getParentNamespace() == currentProgram.getGlobalNamespace()) { String sname = "v_" + cls; st.createLabel(addr, sname, ns, SourceType.USER_DEFINED); lab++; } } } println("IMPORT_RTTI_NAMESPACES " + lab); println("IMPORT_RTTI_FUNCTIONS " + fn); } }