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