GP-2384 prevent variadic override analyzer from examining too many args

This commit is contained in:
James
2022-08-12 15:22:23 +00:00
parent aad60ecdd3
commit fbdcf16498

View File

@@ -21,8 +21,7 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.data.*; import ghidra.program.model.data.*;
import ghidra.program.model.listing.*; import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBufferImpl; import ghidra.program.model.mem.MemoryBufferImpl;
import ghidra.program.model.pcode.PcodeOpAST; import ghidra.program.model.pcode.*;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.SourceType; import ghidra.program.model.symbol.SourceType;
/** /**
@@ -37,7 +36,6 @@ public class PcodeFunctionParser {
// is too short or contains escape characters that thwart the // is too short or contains escape characters that thwart the
// ASCII string analyzer // ASCII string analyzer
private static final int NULL_TERMINATOR_PROBE = -1; private static final int NULL_TERMINATOR_PROBE = -1;
private static final String CALL_INSTRUCTION = "CALL";
private Program program; private Program program;
@@ -62,71 +60,69 @@ public class PcodeFunctionParser {
return null; return null;
} }
List<FunctionCallData> functionCallDataList = new ArrayList<>(); List<FunctionCallData> functionCallDataList = new ArrayList<>();
for (PcodeOpAST ast : pcodeOps) { for (PcodeOpAST callOp : pcodeOps) {
Varnode firstNode = ast.getInput(0); if (callOp.getOpcode() != PcodeOp.CALL) {
if (firstNode == null) {
continue; continue;
} }
if (ast.getMnemonic().contentEquals(CALL_INSTRUCTION)) { Varnode callTarget = callOp.getInput(0);
if (callTarget == null) {
FunctionManager functionManager = this.program.getFunctionManager(); continue;
Function function = functionManager.getFunctionAt(firstNode.getAddress()); }
if (function == null) { FunctionManager functionManager = program.getFunctionManager();
return null; Function function = functionManager.getFunctionAt(callTarget.getAddress());
} if (function == null) {
String functionName = function.getName(); continue;
if (variadicFunctionNames.contains(functionName)) { }
Varnode[] inputs = ast.getInputs(); String functionName = function.getName();
if (inputs.length > 0) { if (!variadicFunctionNames.contains(functionName)) {
boolean hasDefinedFormatString = searchForVariadicCallData(ast, continue;
addressToCandidateData, functionCallDataList, functionName); }
if (!hasDefinedFormatString) { // <= since first input of callOp is call target and
searchForHiddenFormatStrings(ast, functionCallDataList, function); // so not a function argument
} if (callOp.getNumInputs() <= function.getParameterCount()) {
} continue;
} }
boolean hasDefinedFormatString = searchForVariadicCallData(callOp,
addressToCandidateData, functionCallDataList, function);
if (!hasDefinedFormatString) {
searchForHiddenFormatStrings(callOp, functionCallDataList, function);
} }
} }
return functionCallDataList; return functionCallDataList;
} }
private boolean searchForVariadicCallData(PcodeOpAST ast, private boolean searchForVariadicCallData(PcodeOpAST callOp,
Map<Address, Data> addressToCandidateData, List<FunctionCallData> functionCallDataList, Map<Address, Data> addressToCandidateData, List<FunctionCallData> functionCallDataList,
String functionName) { Function function) {
//format string should be last parameter of Function ("..." doesn't count as a parameter)
boolean hasDefinedFormatString = false; //don't subtract 1 since input 0 is the call target
Varnode[] inputs = ast.getInputs(); Varnode v = callOp.getInput(function.getParameterCount());
for (int i = 1; i < inputs.length; i++) { Data data = null;
Varnode v = inputs[i]; Address ramSpaceAddress = convertAddressToRamSpace(v.getAddress());
Data data = null; if (addressToCandidateData.containsKey(ramSpaceAddress)) {
Address ramSpaceAddress = convertAddressToRamSpace(v.getAddress()); data = addressToCandidateData.get(ramSpaceAddress);
if (addressToCandidateData.containsKey(ramSpaceAddress)) { functionCallDataList.add(new FunctionCallData(callOp.getSeqnum().getTarget(),
data = addressToCandidateData.get(ramSpaceAddress); function.getName(), data.getDefaultValueRepresentation()));
functionCallDataList.add(new FunctionCallData(ast.getSeqnum().getTarget(), return true;
functionName, data.getDefaultValueRepresentation())); }
hasDefinedFormatString = true; //check for offcut references into a larger defined string
} Data containing = program.getListing().getDataContaining(ramSpaceAddress);
else { if (containing == null) {
//check for offcut references into a larger defined string return false;
Data containing = program.getListing().getDataContaining(ramSpaceAddress); }
if (containing == null) { if (addressToCandidateData.containsKey(containing.getAddress())) {
continue; StringDataInstance entire = StringDataInstance.getStringDataInstance(containing);
} String subString = entire
if (addressToCandidateData.containsKey(containing.getAddress())) { .getByteOffcut(
StringDataInstance entire =
StringDataInstance.getStringDataInstance(containing);
String subString = entire.getByteOffcut(
(int) (ramSpaceAddress.getOffset() - containing.getAddress().getOffset())) (int) (ramSpaceAddress.getOffset() - containing.getAddress().getOffset()))
.getStringValue(); .getStringValue();
if (subString != null) { if (subString != null) {
functionCallDataList.add(new FunctionCallData(ast.getSeqnum().getTarget(), functionCallDataList.add(new FunctionCallData(callOp.getSeqnum().getTarget(),
functionName, subString)); function.getName(), subString));
hasDefinedFormatString = true; return true;
}
}
} }
} }
return hasDefinedFormatString; return false;
} }
// If addrToCandidateData doesn't have format String data for this call // If addrToCandidateData doesn't have format String data for this call
@@ -135,27 +131,24 @@ public class PcodeFunctionParser {
private void searchForHiddenFormatStrings(PcodeOpAST callOp, private void searchForHiddenFormatStrings(PcodeOpAST callOp,
List<FunctionCallData> functionCallDataList, Function function) { List<FunctionCallData> functionCallDataList, Function function) {
Varnode[] inputs = callOp.getInputs(); int formatStringSlot = function.getParameterCount() - 1;
// Initialize i = 1 to skip first input, which is the call target Parameter param = function.getParameter(formatStringSlot);
for (int i = 1; i < inputs.length; ++i) { if (param == null || param.getSource().equals(SourceType.DEFAULT)) {
Varnode v = inputs[i]; return;
Parameter param = function.getParameter(i - 1); }
if (param == null || param.getSource().equals(SourceType.DEFAULT)) { DataType type = param.getDataType();
continue; if ((type == null) || !(type instanceof Pointer)) {
} return;
DataType type = param.getDataType(); }
if ((type == null) || !(type instanceof Pointer)) { //+1 since first input of callOp is call target address
continue; String formatStringCandidate = findNullTerminatedString(
} callOp.getInput(formatStringSlot + 1).getAddress(), (Pointer) type);
String formatStringCandidate = findNullTerminatedString(v.getAddress(), (Pointer) type); if (formatStringCandidate == null) {
if (formatStringCandidate == null) { return;
continue; }
} if (formatStringCandidate.contains("%")) {
if (formatStringCandidate.contains("%")) { functionCallDataList.add(new FunctionCallData(callOp.getSeqnum().getTarget(),
functionCallDataList.add(new FunctionCallData(callOp.getSeqnum().getTarget(), function.getName(), formatStringCandidate));
function.getName(), formatStringCandidate));
}
break;
} }
} }