/// <inheritdoc /> public override MemoryEntry ReadAnyValueIndex(AnyValue value, MemberIdentifier index) { // TODO: Copy info if (value is AnyStringValue) { // Element of string is one charachter but since PHP has no character type, // it returns string with one character. The character do not need to be initialized SetWarning("Possibly uninitialized string offset"); return(new MemoryEntry(Context.AnyStringValue)); } else if ((value is AnyNumericValue) || (value is AnyBooleanValue) || (value is AnyResourceValue)) { SetWarning("Trying to get element of scalar value", AnalysisWarningCause.ELEMENT_OF_NON_ARRAY_VARIABLE); return(new MemoryEntry(Context.UndefinedValue)); } else if (value is AnyObjectValue) { // TODO: This must be error SetWarning("Cannot use object as array"); return(new MemoryEntry(Context.AnyValue)); } else { // This is case of AnyArrayValue, AnyValue and possibly others. // If value is AnyValue, it can be any object too, so it can cause an error. Value newValue = Context.AnyValue; newValue = FlagsHandler.CopyFlags(value, newValue); return(new MemoryEntry(newValue)); } }
/// <summary> /// For arguments passed by reference: it assignes new values, and copies flags form inputValues. /// </summary> /// <param name="flow">FlowController</param> /// <param name="inputValues">Input values into analyzed function</param> /// <param name="nativeFunctions">Info about analyzed function</param> /// <returns>List of assigned values into aliases</returns> public static List <Value> ResolveAliasArguments(FlowController flow, List <Value> inputValues, List <NativeFunction> nativeFunctions) { List <Value> result = new List <Value>(); MemoryEntry argc = flow.InSet.ReadVariable(new VariableIdentifier(".argument_count")).ReadMemory(flow.OutSet.Snapshot); int argumentCount = ((IntegerValue)argc.PossibleValues.ElementAt(0)).Value; foreach (var nativeFunction in nativeFunctions) { if (nativeFunction.MinArgumentCount <= argumentCount && nativeFunction.MaxArgumentCount >= argumentCount) { int functionArgumentNumber = 0; for (int i = 0; i < argumentCount; i++) { MemoryEntry arg = flow.InSet.ReadVariable(Argument(i)).ReadMemory(flow.InSet.Snapshot); NativeFunctionArgument functionArgument = nativeFunction.Arguments.ElementAt(functionArgumentNumber); if (functionArgument.ByReference == true) { MemoryEntry res = NativeAnalyzerUtils.ResolveReturnValue(functionArgument.Type, flow); res = new MemoryEntry(FlagsHandler.CopyFlags(inputValues, res.PossibleValues)); flow.OutSet.GetVariable(Argument(i)).WriteMemory(flow.OutSet.Snapshot, res); result.AddRange(res.PossibleValues); } //incremeneting functionArgumentNumber if (nativeFunction.Arguments.ElementAt(functionArgumentNumber).Dots == false) { functionArgumentNumber++; } } } } return(result); }
/// <inheritdoc /> public override IEnumerable <Value> WriteStringIndex(StringValue indexed, MemberIdentifier index, MemoryEntry writtenValue) { HashSet <Value> result = new HashSet <Value>(); SimpleStringConverter converter = new SimpleStringConverter(Context); bool isConcrete = false; foreach (var value in converter.Evaluate(writtenValue.PossibleValues, out isConcrete)) { string WrittenChar = value.Value; foreach (var number in ResolveStringIndex(indexed, index)) { Value newValue; if (number < 0) { newValue = indexed; SetWarning("Cannot index string with negative numbers", AnalysisWarningCause.INDEX_OUT_OF_RANGE); } else if (number < indexed.Value.Count()) { StringBuilder newString = new StringBuilder(); newString.Append(indexed.Value); newString[number] = WrittenChar[0]; newValue = FlagsHandler.CopyFlags(indexed, Context.CreateString(newString.ToString())); } else if (number == indexed.Value.Count()) { newValue = FlagsHandler.CopyFlags(indexed, Context.CreateString(indexed.Value + "" + WrittenChar[0].ToString())); } else { newValue = FlagsHandler.CopyFlags(indexed, Context.CreateString(indexed.Value + " " + WrittenChar[0].ToString())); } result.Add(newValue); } } if (!isConcrete) { result.Add(FlagsHandler.CopyFlags(indexed, Context.AnyStringValue)); } return(result); }
/// <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> /// Perform simplification of memory entry /// In some cases resulting memory entry contains leas accurate information /// </summary> /// <param name="entry">Memory entry</param> /// <returns>simplified memory entry</returns> public IEnumerable <Value> Simplify(MemoryEntry entry) { foreach (var value in entry.PossibleValues) { value.Accept(this); } if (booleans.Count >= 2) { result.Add(context.AnyBooleanValue); } else { foreach (var boolean in booleans) { result.Add(boolean); } } if (strings.Count >= 2) { result.Add(FlagsHandler.CopyFlags(strings, context.AnyStringValue)); } else { foreach (var str in strings) { result.Add(str); } } if (containsInt) { if (minInt == maxInt) { result.Add(context.CreateInt(minInt)); } else { result.Add(context.CreateIntegerInterval(minInt, maxInt)); } } if (containsLong) { if (minLong == maxLong) { result.Add(context.CreateLong(minLong)); } else { result.Add(context.CreateLongintInterval(minLong, maxLong)); } } if (containsFloat) { if (minFloat == maxFloat) { result.Add(context.CreateDouble(minFloat)); } else { result.Add(context.CreateFloatInterval(minFloat, maxFloat)); } } return(result); }
/// <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()); }