/// <summary> /// Checks number of arguments in called function. /// </summary> /// <param name="flow">FlowControllers</param> /// <param name="nativeFunctions">NativeFunctions</param> /// <returns>true if the arguments count matches, false otherwise</returns> static public bool checkArgumentsCount(FlowController flow, List <NativeFunction> nativeFunctions) { //check number of arduments MemoryEntry argc = flow.InSet.ReadVariable(new VariableIdentifier(".argument_count")).ReadMemory(flow.OutSet.Snapshot); int argumentCount = ((IntegerValue)argc.PossibleValues.ElementAt(0)).Value; //argument count hassnt been comupted yet if (nativeFunctions.ElementAt(0).MinArgumentCount == -1) { foreach (var nativeFuntion in nativeFunctions) { nativeFuntion.MinArgumentCount = 0; nativeFuntion.MaxArgumentCount = 0; foreach (var nativeFunctionArgument in nativeFuntion.Arguments) { if (nativeFunctionArgument.Dots) { nativeFuntion.MaxArgumentCount = 1000000000; } else if (nativeFunctionArgument.Optional) { nativeFuntion.MaxArgumentCount++; } else { nativeFuntion.MinArgumentCount++; nativeFuntion.MaxArgumentCount++; } } //Console.WriteLine("Name: {0},Min: {1}, Max: {2}", nativeFuntion.Name,nativeFuntion.MinArgumentCount, nativeFuntion.MaxArgumentCount); } } string numberOfArgumentMessage = ""; bool argumentCountMatches = false; foreach (var nativeFunction in nativeFunctions) { if (nativeFunction.MinArgumentCount <= argumentCount && nativeFunction.MaxArgumentCount >= argumentCount) { argumentCountMatches = true; } if (numberOfArgumentMessage != "") { numberOfArgumentMessage += " or"; } if (nativeFunction.MaxArgumentCount >= 1000000000) { if (nativeFunction.MinArgumentCount == 1) { numberOfArgumentMessage += " at least " + nativeFunction.MinArgumentCount + " parameter"; } else { numberOfArgumentMessage += " at least " + nativeFunction.MinArgumentCount + " parameters"; } } else { if (nativeFunction.MaxArgumentCount == nativeFunction.MinArgumentCount) { if (nativeFunction.MinArgumentCount == 1) { numberOfArgumentMessage += " " + nativeFunction.MinArgumentCount + " parameter"; } else { numberOfArgumentMessage += " " + nativeFunction.MinArgumentCount + " parameters"; } } else { numberOfArgumentMessage += " " + nativeFunction.MinArgumentCount + "-" + nativeFunction.MaxArgumentCount + " parameters"; } } } if (argumentCountMatches == false) { string s = ""; if (argumentCount != 1) { s = "s"; } AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisWarning(NativeAnalyzerUtils.GetCallerScript(flow.OutSet), "Function " + nativeFunctions.ElementAt(0).Name.ToString() + " expects" + numberOfArgumentMessage + ", " + argumentCount + " parameter" + s + " given.", flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.WRONG_NUMBER_OF_ARGUMENTS)); return(false); } else { return(true); } }
/// <summary> /// Models constructor of native object /// </summary> /// <param name="flow">FlowController</param> public void initObject(FlowController flow) { var nativeClass = NativeObjectAnalyzer.GetInstance(flow.OutSet).GetClass(ObjectName); var fields = nativeClass.Fields; var thisVariable = flow.OutSet.GetVariable(new VariableIdentifier("this")); List <Value> inputValues = new List <Value>(); foreach (var argument in getArguments(flow)) { inputValues.AddRange(argument.PossibleValues); } MethodIdentifier methodIdentifier = new MethodIdentifier(ObjectName, Method.Name.Name); if (NativeObjectAnalyzer.ReportingFunctions.ContainsKey(methodIdentifier)) { foreach (var flag in NativeObjectAnalyzer.ReportingFunctions[methodIdentifier]) { if (FlagsHandler.IsDirty(inputValues, flag)) { AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisSecurityWarning(NativeAnalyzerUtils.GetCallerScript(flow.OutSet), flow.CurrentPartial, flow.CurrentProgramPoint, flag, methodIdentifier.Name.ToString())); break; } } } foreach (FieldInfo field in fields.Values) { if (field.IsStatic == false) { MemoryEntry fieldValues = NativeAnalyzerUtils.ResolveReturnValue(field.Type, flow); fieldValues = new MemoryEntry(FlagsHandler.CopyFlags(inputValues, fieldValues.PossibleValues)); var fieldEntry = thisVariable.ReadField(flow.OutSet.Snapshot, new VariableIdentifier(field.Name.Value)); fieldEntry.WriteMemory(flow.OutSet.Snapshot, fieldValues); } } }
/// <summary> /// Check type of one argument and reports warnings if they doesn't match. /// </summary> /// <param name="flow">FlowController</param> /// <param name="memoryEntry">Values of argument</param> /// <param name="argument">Information about argument</param> /// <param name="argumentNumber">Number of argument</param> /// <param name="functionName">Name of function</param> /// <param name="warnings">List of warnings, for inserting warnings</param> private static void CheckArgumentTypes(FlowController flow, MemoryEntry memoryEntry, NativeFunctionArgument argument, int argumentNumber, string functionName, List <AnalysisWarning> warnings) { bool argumentMatches = true; foreach (Value value in memoryEntry.PossibleValues) { if (value is AnyValue || value is UndefinedValue) { continue; } switch (argument.Type) { case "mixed": break; case "int": case "integer": //TODO: workaround: type declarations in .xml files specifies the arguments that should be of type number by type int // fix declarations in xml files!! //if (!(ValueTypeResolver.IsInt(value) || ValueTypeResolver.IsLong(value))) if (!(ValueTypeResolver.IsInt(value) || ValueTypeResolver.IsLong(value) || ValueTypeResolver.IsFloat(value))) { argumentMatches = false; } break; case "float": case "number": if (!(ValueTypeResolver.IsInt(value) || ValueTypeResolver.IsLong(value) || ValueTypeResolver.IsFloat(value))) { argumentMatches = false; } break; case "string": case "char": if (!ValueTypeResolver.IsString(value)) { argumentMatches = false; } break; case "array": if (!ValueTypeResolver.IsArray(value)) { argumentMatches = false; } break; case "object": if (!ValueTypeResolver.IsObject(value)) { argumentMatches = false; } break; case "bool": case "boolean": if (!ValueTypeResolver.IsBool(value)) { argumentMatches = false; } break; case "resource": case "resouce": if (!(value is AnyResourceValue)) { argumentMatches = false; } break; case "callable": case "callback": if (!ValueTypeResolver.IsString(value) && !(value is FunctionValue)) { argumentMatches = false; } break; case "void": throw new Exception("Void is not a type of argument"); default: if (!ValueTypeResolver.IsObject(value)) { argumentMatches = false; } break; } } if (argumentMatches == false) { warnings.Add(new AnalysisWarning(NativeAnalyzerUtils.GetCallerScript(flow.OutSet), "Wrong type of argument number " + argumentNumber + " in function " + functionName + ", expecting " + argument.Type, flow.CurrentPartial, flow.CurrentProgramPoint, AnalysisWarningCause.WRONG_ARGUMENTS_TYPE)); } }
/// <summary> /// Models a called method. /// </summary> /// <param name="flow"></param> public void Analyze(FlowController flow) { if (NativeAnalyzerUtils.checkArgumentsCount(flow, Method)) { NativeAnalyzerUtils.checkArgumentTypes(flow, Method); } MethodIdentifier methodIdentifier = new MethodIdentifier(ObjectName, Method.Name.Name); var nativeClass = NativeObjectAnalyzer.GetInstance(flow.OutSet).GetClass(ObjectName); var fields = nativeClass.Fields; var functionResult = NativeAnalyzerUtils.ResolveReturnValue(Method.ReturnType, flow); var arguments = getArguments(flow); var thisVariable = flow.OutSet.GetVariable(new VariableIdentifier("this")); List <Value> inputValues = new List <Value>(); bool isStaticCall = false; if (thisVariable.ReadMemory(flow.OutSet.Snapshot).PossibleValues.Count() == 1 && thisVariable.ReadMemory(flow.OutSet.Snapshot).PossibleValues.First() is UndefinedValue) { isStaticCall = true; var fieldsEntries = new List <MemoryEntry>(); foreach (FieldInfo field in fields.Values) { var fieldEntry = thisVariable.ReadField(flow.OutSet.Snapshot, new VariableIdentifier(field.Name.Value)); fieldsEntries.Add(fieldEntry.ReadMemory(flow.OutSet.Snapshot)); inputValues.AddRange(fieldEntry.ReadMemory(flow.OutSet.Snapshot).PossibleValues); } fieldsEntries.AddRange(arguments); foreach (FieldInfo field in fields.Values) { var fieldEntry = thisVariable.ReadField(flow.OutSet.Snapshot, new VariableIdentifier(field.Name.Value)); MemoryEntry newfieldValues = NativeAnalyzerUtils.ResolveReturnValue(field.Type, flow); newfieldValues = new MemoryEntry(FlagsHandler.CopyFlags(inputValues, newfieldValues.PossibleValues)); HashSet <Value> newValues = new HashSet <Value>((fieldEntry.ReadMemory(flow.OutSet.Snapshot)).PossibleValues); foreach (var newValue in newfieldValues.PossibleValues) { newValues.Add(newValue); } thisVariable.ReadField(flow.OutSet.Snapshot, new VariableIdentifier(field.Name.Value)).WriteMemory(flow.OutSet.Snapshot, new MemoryEntry(newValues)); } } foreach (var argument in arguments) { inputValues.AddRange(argument.PossibleValues); } if (NativeObjectAnalyzer.ReportingFunctions.ContainsKey(methodIdentifier)) { foreach (var flag in NativeObjectAnalyzer.ReportingFunctions[methodIdentifier]) { if (FlagsHandler.IsDirty(inputValues, flag)) { AnalysisWarningHandler.SetWarning(flow.OutSet, new AnalysisSecurityWarning(NativeAnalyzerUtils.GetCallerScript(flow.OutSet), flow.CurrentPartial, flow.CurrentProgramPoint, flag, methodIdentifier.Name.ToString())); break; } } } if (isStaticCall == true) { thisVariable.WriteMemory(flow.OutSet.Snapshot, new MemoryEntry(FlagsHandler.CopyFlags(inputValues, thisVariable.ReadMemory(flow.OutSet.Snapshot).PossibleValues))); } functionResult = new MemoryEntry(FlagsHandler.CopyFlags(inputValues, functionResult.PossibleValues)); if (NativeObjectAnalyzer.CleaningFunctions.ContainsKey(methodIdentifier)) { foreach (var flag in NativeObjectAnalyzer.CleaningFunctions[methodIdentifier]) { functionResult = new MemoryEntry(FlagsHandler.Clean(functionResult.PossibleValues, flag)); } } flow.OutSet.GetLocalControlVariable(SnapshotBase.ReturnValue).WriteMemory(flow.OutSet.Snapshot, functionResult); var assigned_aliases = NativeAnalyzerUtils.ResolveAliasArguments(flow, inputValues, (new NativeFunction[1] { Method }).ToList()); }