mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 01:39:21 +02:00
242 lines
8.7 KiB
Java
242 lines
8.7 KiB
Java
/* ###
|
|
* IP: GHIDRA
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
// VxWorksSymTab_6_1 is an adaptation of the vxWorksSymTab script. It was modified by a customer
|
|
// to use a single loop, instead of two. It also added demangling of C++ symbol names - at least
|
|
// those that Ghidra knows how to demangle.
|
|
//
|
|
// Extracts all symbols in a VxWorks symbol table and disassembles
|
|
// the global functions. Any existing symbols in the Ghidra symbol table
|
|
// that collide with symbols defined in the VxWorks symbol table are deleted.
|
|
//
|
|
// The VxWorks symbol table is an array of symbol table entries [0..n-1]
|
|
// followed by a 32-bit value that is equal to n (number of sym tbl entries).
|
|
// Each entry in the array has the following structure:
|
|
//
|
|
// // Total size: 0x18 (24) bytes
|
|
// 0x00 int NULL
|
|
// 0x04 char *symNameAddr // symbol name
|
|
// 0x08 void *symLocAddr // location of object named by symbol
|
|
// 0x0c int NULL
|
|
// 0x10 int NULL
|
|
// 0x14 uchar symType // see switch statement below
|
|
// 0x15 uchar fill[3]
|
|
//
|
|
// The script requests:
|
|
// - Output file name: Each symbol name and address is recorded here.
|
|
// (Errors are also logged to this file.)
|
|
// - Address of "number of symbols" value: At the end of the symbol table,
|
|
// its length is recorded as a 32-bit integer. The
|
|
// script needs the address of that value to calculate
|
|
// the symbol table's start address.
|
|
//
|
|
// @category Customer Submission.vxWorks
|
|
|
|
import java.io.FileOutputStream;
|
|
import java.io.PrintWriter;
|
|
import java.util.List;
|
|
|
|
import ghidra.app.cmd.label.DemanglerCmd;
|
|
import ghidra.app.script.GhidraScript;
|
|
import ghidra.app.util.demangler.DemangledException;
|
|
import ghidra.app.util.demangler.MangledContext;
|
|
import ghidra.app.util.demangler.gnu.GnuDemangler;
|
|
import ghidra.program.model.address.Address;
|
|
import ghidra.program.model.mem.Memory;
|
|
import ghidra.program.model.symbol.*;
|
|
|
|
public class VxWorksSymTab_6_1 extends GhidraScript {
|
|
|
|
static final int SYM_ENTRY_SIZE = 24;
|
|
static final int SYM_NAME_OFF = 4;
|
|
static final int SYM_LOC_OFF = 8;
|
|
static final int SYM_TYPE_OFF = 0x14;
|
|
|
|
@Override
|
|
public void run() throws Exception {
|
|
|
|
// Get Memory and SymbolTable objects (used later)
|
|
Memory mem = currentProgram.getMemory();
|
|
SymbolTable ghidraSymTbl = currentProgram.getSymbolTable();
|
|
|
|
// Open output file
|
|
// All symbols found (address and name) will be logged to this file
|
|
try (PrintWriter output = new PrintWriter(
|
|
new FileOutputStream(askFile("vxWorks Symbol Table Parser", "Output file name?")))) {
|
|
|
|
// Get address of "total number of sym tbl entries" value
|
|
Address vxNumSymEntriesAddr = askAddress("vxWorks Symbol Table Parser",
|
|
"Address of \"total number of symbol table entries\" value?");
|
|
int vxNumSymEntries = mem.getInt(vxNumSymEntriesAddr);
|
|
println("VxWorks symbol table has " + vxNumSymEntries + " entries");
|
|
|
|
// Create a GNU demangler instance
|
|
GnuDemangler demangler = new GnuDemangler();
|
|
if (!demangler.canDemangle(currentProgram)) {
|
|
println("Unable to create demangler.");
|
|
return;
|
|
}
|
|
|
|
// Process entries in VxWorks symbol table
|
|
Address vxSymTbl = vxNumSymEntriesAddr.subtract(vxNumSymEntries * SYM_ENTRY_SIZE);
|
|
for (int i = 0; i < vxNumSymEntries; i++) {
|
|
|
|
if (monitor.isCancelled()) {
|
|
return; // check for cancel button
|
|
}
|
|
println("i=" + i); // visual counter
|
|
|
|
// Extract symbol table entry values
|
|
Address symEntry = vxSymTbl.add(i * SYM_ENTRY_SIZE);
|
|
Address symNameAddr = toAddr(mem.getInt(symEntry.add(SYM_NAME_OFF)));
|
|
Address symLocAddr = toAddr(mem.getInt(symEntry.add(SYM_LOC_OFF)));
|
|
byte symType = mem.getByte(symEntry.add(SYM_TYPE_OFF));
|
|
println("symNameAddr: 0x" + symNameAddr.toString() + ", symLocAddr: 0x" +
|
|
symLocAddr.toString() + ", symType: " + symType);
|
|
|
|
// Remove any data or instructions that overlap this symName
|
|
// (May happen if disassembly creates invalid references)
|
|
Address a;
|
|
String symName;
|
|
for (a = symNameAddr; mem.getByte(a) != 0; a = a.add(1)) {
|
|
if (getDataAt(a) != null) {
|
|
removeDataAt(a);
|
|
}
|
|
if (getInstructionAt(a) != null) {
|
|
removeInstructionAt(a);
|
|
}
|
|
}
|
|
if (getDataAt(a) != null) {
|
|
removeDataAt(a);
|
|
}
|
|
if (getInstructionAt(a) != null) {
|
|
removeInstructionAt(a);
|
|
}
|
|
|
|
// Turn *symNameAddr into a string and store it in symName
|
|
try {
|
|
symName = (String) createAsciiString(symNameAddr).getValue();
|
|
}
|
|
catch (Exception e) {
|
|
println("createAsciiString: caught exception...");
|
|
println(e.getMessage());
|
|
return;
|
|
}
|
|
println("symName: " + symName);
|
|
|
|
// Demangle symName
|
|
String symDemangledName = null;
|
|
try {
|
|
// if successful, symDemangledName will be non-NULL
|
|
MangledContext mangledContext = demangler.createMangledContext(symDemangledName,
|
|
null, currentProgram, symNameAddr);
|
|
symDemangledName = demangler.demangle(mangledContext).getSignature(false);
|
|
}
|
|
catch (DemangledException e) {
|
|
// if symName wasn't a mangled name, silently continue
|
|
if (!e.isInvalidMangledName()) {
|
|
println("demangle: Demangling error");
|
|
output.println("demangle: Demangling error");
|
|
}
|
|
}
|
|
catch (RuntimeException e) {
|
|
println("demangle: Caught runtime exception");
|
|
output.println("demangle: Caught runtime exception");
|
|
}
|
|
if (symDemangledName != null) {
|
|
println("symDemangledName: " + symDemangledName);
|
|
}
|
|
|
|
// Delete any symbol in the Ghidra symbol table with the same name
|
|
SymbolIterator syms = ghidraSymTbl.getSymbols(symName);
|
|
Symbol sym;
|
|
while (syms.hasNext()) {
|
|
sym = syms.next();
|
|
println("Deleting matching Ghidra symbol: " + sym.getName());
|
|
ghidraSymTbl.removeSymbolSpecial(sym);
|
|
}
|
|
|
|
// Delete any symbol in the Ghidra symbol table at the same address
|
|
if ((sym = getSymbolAt(symLocAddr)) != null) {
|
|
println("Deleting symbol at target address: " + sym.getName());
|
|
ghidraSymTbl.removeSymbolSpecial(sym);
|
|
}
|
|
|
|
switch (symType) {
|
|
case 0: // Undefined Symbol
|
|
println("NULL symType!");
|
|
break;
|
|
case 2: // Local Absolute
|
|
case 3: // Global Absolute
|
|
case 6: // Local Data
|
|
case 7: // Global Data
|
|
case 8: // Local BSS
|
|
case 9: // Global BSS
|
|
// Data: log the symbol & create a Ghidra symbol at symLocAddr
|
|
output.println(symLocAddr.toString() + "\t" + symName);
|
|
createLabel(symLocAddr, symName, true);
|
|
if (symDemangledName != null) {
|
|
new DemanglerCmd(symLocAddr, symName).applyTo(currentProgram, monitor);
|
|
List<Symbol> symbols =
|
|
getSymbols(symName, currentProgram.getGlobalNamespace());
|
|
if (!symbols.isEmpty()) {
|
|
ghidraSymTbl.removeSymbolSpecial(symbols.get(0));
|
|
}
|
|
}
|
|
break;
|
|
case 4: // Local .text
|
|
case 5: // Global .text
|
|
// Code: log the symbol, disassemble, & create/name function
|
|
output.println(symLocAddr.toString() + "\t" + symName);
|
|
goTo(symLocAddr);
|
|
disassemble(symLocAddr);
|
|
createFunction(symLocAddr, symName);
|
|
if (getFunctionAt(symLocAddr) != null) {
|
|
getFunctionAt(symLocAddr).setName(symName, SourceType.USER_DEFINED);
|
|
if (symDemangledName != null) {
|
|
new DemanglerCmd(symLocAddr, symName).applyTo(currentProgram,
|
|
monitor);
|
|
List<Symbol> symbols =
|
|
getSymbols(symName, currentProgram.getGlobalNamespace());
|
|
if (!symbols.isEmpty()) {
|
|
ghidraSymTbl.removeSymbolSpecial(symbols.get(0));
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
println("createFunction: Failed to create function");
|
|
output.println("createFunction: Failed to create function");
|
|
createLabel(symLocAddr, symName, true);
|
|
if (symDemangledName != null) {
|
|
new DemanglerCmd(symLocAddr, symName).applyTo(currentProgram,
|
|
monitor);
|
|
List<Symbol> symbols =
|
|
getSymbols(symName, currentProgram.getGlobalNamespace());
|
|
if (!symbols.isEmpty()) {
|
|
ghidraSymTbl.removeSymbolSpecial(symbols.get(0));
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
println("Invalid symType!");
|
|
break;
|
|
}
|
|
|
|
symEntry = symEntry.add(SYM_ENTRY_SIZE); // goto next entry
|
|
}
|
|
}
|
|
}
|
|
}
|