// Seed NE entry points that Ghidra 12.1's automatic analysis leaves undefined. // @category TDKPIN import ghidra.app.script.GhidraScript; import ghidra.program.model.address.Address; import ghidra.program.model.data.ArrayDataType; import ghidra.program.model.data.ByteDataType; import ghidra.program.model.data.WordDataType; import ghidra.program.model.listing.Function; import ghidra.program.model.symbol.SourceType; public class SeedMissingEntrypoints extends GhidraScript { @Override public void run() throws Exception { // Segment tags, compiler tables, and embedded Real48 constants must be // defined before missed code is disassembled so linear sweep cannot // consume them as instructions. defineWords("1000:0000", 1, "code_segment_1_tag"); defineWords("1000:026e", 1, "code1_embedded_word_026e"); defineWords("1008:0000", 1, "code_segment_2_tag"); defineWords("1008:0f2c", 1, "code2_embedded_word_0f2c"); defineWords("1008:11bd", 4, "code2_embedded_words_11bd"); defineWords("1008:131e", 4, "code2_embedded_words_131e"); defineWords("1010:0000", 1, "code_segment_3_tag"); defineWords("1010:0470", 1, "code3_embedded_word_0470"); defineWords("1018:0000", 1, "code_segment_4_tag"); defineWords("1020:0000", 1, "code_segment_5_tag"); defineBytes("1020:0107", 38, "borland_runtime_copyright"); defineBytes("1020:1191", 42, "real48_table_1191"); defineBytes("1020:1240", 36, "real48_table_1240"); defineBytes("1020:12d7", 48, "real48_table_12d7"); defineBytes("1020:13e8", 78, "real48_table_13e8"); seed("1000:eaB1", "exported_ordinal_10"); seed("1000:fd85", "ne_program_entry"); // Ghidra's NE entry analysis misses a set of unreferenced Borland // runtime routines in Code5. These starts are backed by complete x86 // prologue/control-flow/return sequences in the target bytes. seed("1020:0195", "runtime_1020_0195"); seed("1020:03c5", "runtime_1020_03c5"); seed("1020:046c", "runtime_1020_046c"); seed("1020:048f", "runtime_1020_048f"); seed("1020:049f", "runtime_1020_049f"); seed("1020:04fc", "runtime_1020_04fc"); seed("1020:0710", "runtime_1020_0710"); seed("1020:0760", "runtime_1020_0760"); seed("1020:0796", "runtime_1020_0796"); seed("1020:0866", "runtime_1020_0866"); seed("1020:098c", "runtime_1020_098c"); seed("1020:09af", "runtime_1020_09af"); seed("1020:09d2", "runtime_1020_09d2"); seed("1020:0aee", "runtime_1020_0aee"); seed("1020:103b", "runtime_1020_103b"); seed("1020:1045", "runtime_1020_1045"); seed("1020:1059", "runtime_1020_1059"); seed("1020:10aa", "runtime_1020_10aa"); seed("1020:111d", "runtime_1020_111d"); seed("1020:11bb", "runtime_1020_11bb"); seed("1020:1264", "runtime_1020_1264"); seed("1020:1307", "runtime_1020_1307"); seed("1020:1436", "runtime_1020_1436"); seed("1020:14de", "runtime_1020_14de"); seed("1020:1539", "runtime_1020_1539"); seed("1020:16dd", "runtime_1020_16dd"); // These are proven code bytes that either complete an existing // function or form an alternate entry sharing a tail with one. Ghidra // does not permit all such Borland entry variants to be separate, // overlapping function bodies, but the instruction bytes still belong // in executable coverage and the reconstruction ledger. disassembleOnly("1018:012f"); disassembleOnly("1020:0531"); disassembleOnly("1020:0582"); disassembleOnly("1020:0666"); disassembleOnly("1020:06b4"); disassembleOnly("1020:0767"); disassembleOnly("1020:079d"); disassembleOnly("1020:100f"); analyzeAll(currentProgram); } private void defineWords(String text, int count, String name) throws Exception { Address address = toAddr(text); if (getDataAt(address) == null) { createData(address, new ArrayDataType(WordDataType.dataType, count, 2)); } createLabel(address, name, true); println("Defined " + count + " word(s) at " + address + " as " + name); } private void defineBytes(String text, int count, String name) throws Exception { Address address = toAddr(text); if (getDataAt(address) == null) { createData(address, new ArrayDataType(ByteDataType.dataType, count, 1)); } createLabel(address, name, true); println("Defined " + count + " byte(s) at " + address + " as " + name); } private void disassembleOnly(String text) { Address address = toAddr(text); disassemble(address); println("Disassembled shared/tail entry at " + address); } private void seed(String text, String name) throws Exception { Address address = toAddr(text); disassemble(address); Function function = getFunctionAt(address); if (function == null) { function = createFunction(address, name); } if (function != null && !name.equals(function.getName())) { function.setName(name, SourceType.USER_DEFINED); } println("Seeded " + name + " at " + address); } }