package symbol; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import bil.Expression; import bil.Variable; import internal.HelperFunctions; import internal.TermCreator; import term.Arg; import term.Tid; import ghidra.program.model.address.Address; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.FunctionManager; import ghidra.program.model.listing.Parameter; import ghidra.program.model.pcode.Varnode; import ghidra.program.model.symbol.SymbolTable; public class ExternSymbolCreator { public static HashMap<String, ExternSymbol> externalSymbolMap = new HashMap<String, ExternSymbol>(); // private constructor for non-instantiable classes private ExternSymbolCreator() { throw new UnsupportedOperationException(); } /** * * @param symTab: symbol table * * Creates a map of external symbols to add to the program term */ public static void createExternalSymbolMap(SymbolTable symTab) { HashMap<String, ArrayList<Function>> symbolMap = new HashMap<String, ArrayList<Function>>(); HelperFunctions.funcMan.getExternalFunctions().forEach(func -> { ArrayList<Function> thunkFuncs = new ArrayList<Function>(); getThunkFunctions(func, thunkFuncs); if(thunkFuncs.size() > 0) { for(Function thunk : thunkFuncs) { addToSymbolMap(symbolMap, thunk); } } else { addToSymbolMap(symbolMap, func); } }); createExternalSymbols(symbolMap); } /** * * @param func: Function for which thunk functions are to be found * @param thunkFuncs: List of found thunk functions * * Recursively find thunk functions in symbol chain */ public static void getThunkFunctions(Function func, ArrayList<Function> thunkFuncs) { Address[] thunks = func.getFunctionThunkAddresses(); if(thunks != null) { for(Address thunkAddr : thunks) { Function thunkFunction = HelperFunctions.funcMan.getFunctionAt(thunkAddr); thunkFuncs.add(thunkFunction); getThunkFunctions(thunkFunction, thunkFuncs); } } } /** * * @param symbolMap: Maps symbol names to multiple function declarations * @param func: Function to be added to symbol map * * Either adds a function to a given symbol name or creates a new entry in the symbol map */ public static void addToSymbolMap(HashMap<String, ArrayList<Function>> symbolMap, Function func) { if(symbolMap.containsKey(func.getName())) { symbolMap.get(func.getName()).add(func); } else { symbolMap.put(func.getName(), new ArrayList<Function>(){{add(func);}}); } } /** * @param symbolMap: External symbol map * * Creates external symbol map with an unique TID, a calling convention and argument objects. */ public static void createExternalSymbols(HashMap<String, ArrayList<Function>> symbolMap) { for(Map.Entry<String, ArrayList<Function>> functions : symbolMap.entrySet()) { ExternSymbol extSym = new ExternSymbol(); extSym.setName(functions.getKey()); for(Function func : functions.getValue()) { if(HelperFunctions.sameSymbolNameNotCallingCurrentSymbol(func)) { extSym.setTid(new Tid(String.format("sub_%s", func.getEntryPoint().toString()), func.getEntryPoint().toString())); extSym.setNoReturn(func.hasNoReturn()); extSym.setArguments(createArguments(func)); extSym.setCallingConvention(HelperFunctions.funcMan.getDefaultCallingConvention().toString()); extSym.setHasVarArgs(func.hasVarArgs()); } if(!func.isExternal()) { extSym.getAddresses().add(func.getEntryPoint().toString()); } } externalSymbolMap.put(functions.getKey(), extSym); } } /** * * @param flow: flow from instruction to target * @param targetAddress: address of target * @param funcMan: function manager * * Adds function pointer address to external symbol and updates the TID. */ public static Tid updateExternalSymbolLocations(Address flow, String targetAddress, FunctionManager funcMan) { Function external = funcMan.getFunctionAt(flow); ExternSymbol symbol = externalSymbolMap.get(external.getName()); symbol.getAddresses().add(targetAddress); if(symbol.getTid().getId().startsWith("sub_EXTERNAL")) { Tid targetTid = new Tid(String.format("sub_%s", targetAddress), targetAddress); HelperFunctions.functionEntryPoints.put(targetAddress, targetTid); symbol.setTid(targetTid); return targetTid; } return symbol.getTid(); } /** * @param param: Function parameter * @return: new Arg * * Specifies if the argument is a stack variable or a register. */ public static Arg specifyArg(Parameter param) { Arg arg = new Arg(); if (param.isStackVariable()) { Variable stackVar = TermCreator.createVariable(param.getFirstStorageVarnode()); arg.setLocation(new Expression("LOAD", stackVar)); } else if (param.isRegisterVariable()) { arg.setVar(HelperFunctions.checkForParentRegister(param.getFirstStorageVarnode())); } arg.setIntent("INPUT"); return arg; } /** * @param func: function to get arguments * @return: new Arg ArrayList * * Creates Arguments for the ExternSymbol object. */ public static ArrayList<Arg> createArguments(Function func) { ArrayList<Arg> args = new ArrayList<Arg>(); Parameter[] params = func.getParameters(); for (Parameter param : params) { args.add(specifyArg(param)); } if (!HelperFunctions.hasVoidReturn(func)) { for(Varnode node : func.getReturn().getVariableStorage().getVarnodes()) { args.add(new Arg(HelperFunctions.checkForParentRegister(node), "OUTPUT")); } } return args; } }