diff --git a/CryptoAnalysis/src/main/java/crypto/extractparameter/transformation/OperatorTransformation.java b/CryptoAnalysis/src/main/java/crypto/extractparameter/transformation/OperatorTransformation.java index 2a13024d6..f3a7bb8c3 100644 --- a/CryptoAnalysis/src/main/java/crypto/extractparameter/transformation/OperatorTransformation.java +++ b/CryptoAnalysis/src/main/java/crypto/extractparameter/transformation/OperatorTransformation.java @@ -19,6 +19,8 @@ import java.util.Collection; import java.util.Collections; import java.util.HashSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class OperatorTransformation extends AbstractTransformation implements ITransformation { @@ -36,6 +38,13 @@ public Collection computeRequiredValues(Statement statement) { return Collections.singleton(lengthOp); } + if (frameworkHandler.isBinaryExpr(rightOp) && isArithmeticExpression(statement)) { + // Try to extract operands from the binary expression + Collection operands = extractArithmeticOperands(rightOp, statement); + if (!operands.isEmpty()) { + return operands; + } + } } return Collections.emptySet(); @@ -51,6 +60,9 @@ public Collection transformAllocationSite( if (rightOp.isLengthExpr()) { return evaluateLengthExpr(allocVal, rightOp, graph, transformation); } + if (frameworkHandler.isBinaryExpr(rightOp) && isArithmeticExpression(statement)) { + return evaluateArithmeticExpression(allocVal, rightOp, graph, transformation); + } } return Collections.emptySet(); @@ -102,4 +114,104 @@ private Collection evaluateLengthExpr( return transformedValues; } + + private boolean isArithmeticExpression(Statement statement) { + String stmtStr = statement.toString(); + + // Look for arithmetic patterns but exclude string operations and method calls + boolean hasArithmetic = stmtStr.contains(" + ") || stmtStr.contains(" - ") || + stmtStr.contains(" * ") || stmtStr.contains(" / ") || + stmtStr.contains(" % "); + + // Make sure it's not a method call or string operation + boolean isMethodCall = stmtStr.contains("invoke") || stmtStr.contains("."); + boolean isStringConcat = stmtStr.contains("\"") && stmtStr.contains(" + "); + + return hasArithmetic && !isMethodCall && !isStringConcat; + } + + private Collection extractArithmeticOperands(Val binaryExpr, Statement statement) { + if (isConstantArithmetic(statement.toString())) { + return Collections.emptySet(); + } + return Collections.emptySet(); + } + + private Collection evaluateArithmeticExpression( + AllocVal allocVal, Val binaryExpr, AllocationSiteGraph graph, TransformationHandler transformation) { + + Statement statement = allocVal.getAllocStatement(); + String stmtStr = statement.toString(); + + // Handle constant arithmetic first + if (isConstantArithmetic(stmtStr)) { + return evaluateConstantArithmetic(allocVal, stmtStr); + } + return createUnknownTransformedValue(allocVal); + } + + private boolean isConstantArithmetic(String statementStr) { + // Match patterns like: var = number operator number + Pattern constantPattern = Pattern.compile(".*=\\s*(-?\\d+)\\s*([+\\-*/])\\s*(-?\\d+).*"); + return constantPattern.matcher(statementStr).matches(); + } + + private Collection evaluateConstantArithmetic(AllocVal allocVal, String statementStr) { + try { + // Extract numbers and operator using regex + Pattern pattern = Pattern.compile(".*=\\s*(-?\\d+)\\s*([+\\-*/])\\s*(-?\\d+).*"); + Matcher matcher = pattern.matcher(statementStr); + + if (matcher.matches()) { + int leftValue = Integer.parseInt(matcher.group(1)); + String operator = matcher.group(2); + int rightValue = Integer.parseInt(matcher.group(3)); + + Integer result = performArithmeticOperation(leftValue, rightValue, operator); + + if (result != null) { + Method method = allocVal.getAllocStatement().getMethod(); + Val intVal = frameworkHandler.createIntConstant(result, method); + + TransformedValue value = new TransformedValue(intVal, allocVal.getAllocStatement(), Collections.emptySet()); + return Collections.singleton(value); + } + } + } catch (Exception e) { + } + + return createUnknownTransformedValue(allocVal); + } + + private Integer performArithmeticOperation(int left, int right, String operator) { + try { + switch (operator) { + case "+": + return Math.addExact(left, right); + case "-": + return Math.subtractExact(left, right); + case "*": + return Math.multiplyExact(left, right); + case "/": + if (right == 0) return null; + return left / right; + case "%": + if (right == 0) return null; + return left % right; + default: + return null; + } + } catch (ArithmeticException e) { + return null; + } + } + + private Collection createUnknownTransformedValue(AllocVal allocVal) { + TransformedValue unknownValue = new TransformedValue( + allocVal.getAllocVal(), + allocVal.getAllocStatement(), + Collections.emptySet(), + Collections.emptySet()); + return Collections.singleton(unknownValue); + } } diff --git a/CryptoAnalysis/src/main/java/crypto/extractparameter/transformation/StringTransformation.java b/CryptoAnalysis/src/main/java/crypto/extractparameter/transformation/StringTransformation.java index 03e594399..028a91f2f 100644 --- a/CryptoAnalysis/src/main/java/crypto/extractparameter/transformation/StringTransformation.java +++ b/CryptoAnalysis/src/main/java/crypto/extractparameter/transformation/StringTransformation.java @@ -59,6 +59,29 @@ public class StringTransformation extends AbstractTransformation implements ITra "java.lang.String", List.of("java.lang.CharSequence", "java.lang.CharSequence")); + private final MethodWrapper CONCAT = + new MethodWrapper("java.lang.String", "concat", "java.lang.String", List.of("java.lang.String")); + + private final MethodWrapper STARTS_WITH = + new MethodWrapper("java.lang.String", "startsWith", "boolean", List.of("java.lang.String")); + + private final MethodWrapper ENDS_WITH = + new MethodWrapper("java.lang.String", "endsWith", "boolean", List.of("java.lang.String")); + + private final MethodWrapper TRIM = + new MethodWrapper("java.lang.String", "trim", "java.lang.String"); + + private final MethodWrapper SUBSTRING_ONE_PARAM = + new MethodWrapper("java.lang.String", "substring", "java.lang.String", List.of("int")); + private final MethodWrapper SUBSTRING_TWO_PARAMS = + new MethodWrapper("java.lang.String", "substring", "java.lang.String", List.of("int", "int")); + + private final MethodWrapper CHAR_AT = + new MethodWrapper("java.lang.String", "charAt", "char", List.of("int")); + + private final MethodWrapper INDEX_OF = + new MethodWrapper("java.lang.String", "indexOf", "int", List.of("java.lang.String")); + public StringTransformation(FrameworkHandler frameworkHandler) { super(frameworkHandler); } @@ -94,6 +117,47 @@ public Collection computeRequiredValues(Statement statement) { return Set.of(base, arg1, arg2); } + if (calledMethod.equals(CONCAT)) { + Val base = invokeExpr.getBase(); + Val arg = invokeExpr.getArg(0); + return Set.of(base, arg); + } + + if (Set.of(STARTS_WITH, ENDS_WITH).contains(calledMethod)) { + Val base = invokeExpr.getBase(); + Val pattern = invokeExpr.getArg(0); + return Set.of(base, pattern); + } + + if (calledMethod.equals(TRIM)) { + Val base = invokeExpr.getBase(); + return Set.of(base); + } + + if (Set.of(SUBSTRING_ONE_PARAM, SUBSTRING_TWO_PARAMS).contains(calledMethod)) { + Val base = invokeExpr.getBase(); + Val beginIndex = invokeExpr.getArg(0); + + if (calledMethod.equals(SUBSTRING_TWO_PARAMS)) { + Val endIndex = invokeExpr.getArg(1); + return Set.of(base, beginIndex, endIndex); + } else { + return Set.of(base, beginIndex); + } + } + + if (calledMethod.equals(CHAR_AT)) { + Val base = invokeExpr.getBase(); + Val index = invokeExpr.getArg(0); + return Set.of(base, index); + } + + if (calledMethod.equals(INDEX_OF)) { + Val base = invokeExpr.getBase(); + Val searchStr = invokeExpr.getArg(0); + return Set.of(base, searchStr); + } + return Collections.emptySet(); } @@ -124,6 +188,30 @@ public Collection transformAllocationSite( return evaluateReplace(allocVal, graph, transformation); } + if (methodWrapper.equals(CONCAT)) { + return evaluateConcat(allocVal, graph, transformation); + } + + if (Set.of(STARTS_WITH, ENDS_WITH).contains(methodWrapper)) { + return evaluateStartsEndsWith(allocVal, graph, transformation); + } + + if (methodWrapper.equals(TRIM)) { + return evaluateTrim(allocVal, graph, transformation); + } + + if (Set.of(SUBSTRING_ONE_PARAM, SUBSTRING_TWO_PARAMS).contains(methodWrapper)) { + return evaluateSubstring(allocVal, graph, transformation); + } + + if (methodWrapper.equals(CHAR_AT)) { + return evaluateCharAt(allocVal, graph, transformation); + } + + if (methodWrapper.equals(INDEX_OF)) { + return evaluateIndexOf(allocVal, graph, transformation); + } + return Collections.emptySet(); } @@ -334,4 +422,433 @@ private Collection evaluateReplace( return transformedValues; } + + private Collection evaluateConcat( + AllocVal allocVal, AllocationSiteGraph graph, TransformationHandler transformation) { + Statement statement = allocVal.getAllocStatement(); + InvokeExpr invokeExpr = statement.getInvokeExpr(); + + Val base = invokeExpr.getBase(); + Val arg = invokeExpr.getArg(0); + + Collection baseAllocSites = graph.getAllocSites(base); + Collection argAllocSites = graph.getAllocSites(arg); + + Collection extractedBaseValues = new HashSet<>(); + for (AllocVal baseAllocSite : baseAllocSites) { + Collection values = transformation.transformAllocationSite(baseAllocSite, graph); + extractedBaseValues.addAll(values); + } + + Collection extractedArgValues = new HashSet<>(); + for (AllocVal argAllocSite : argAllocSites) { + Collection values = transformation.transformAllocationSite(argAllocSite, graph); + extractedArgValues.addAll(values); + } + + Collection transformedValues = new HashSet<>(); + for (TransformedValue extractedBase : extractedBaseValues) { + for (TransformedValue extractedArg : extractedArgValues) { + Collection knownValues = new HashSet<>(); + Collection unknownValues = new HashSet<>(); + + if (extractedBase.getTransformedVal().isStringConstant()) { + knownValues.add(extractedBase); + } else { + unknownValues.add(extractedBase); + } + + if (extractedArg.getTransformedVal().isStringConstant()) { + knownValues.add(extractedArg); + } else { + unknownValues.add(extractedArg); + } + + if (!unknownValues.isEmpty()) { + // At least one variable is not a String -> Cannot evaluate 's.concat(arg)' + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } else { + // Evaluate 's.concat(arg)' + String baseString = extractedBase.getTransformedVal().getStringValue(); + String argString = extractedArg.getTransformedVal().getStringValue(); + String transformedString = baseString + argString; + + Val stringVal = frameworkHandler.createStringConstant( + transformedString, statement.getMethod()); + TransformedValue value = new TransformedValue(stringVal, statement, knownValues); + transformedValues.add(value); + } + } + } + + return transformedValues; + } + + private Collection evaluateStartsEndsWith( + AllocVal allocVal, AllocationSiteGraph graph, TransformationHandler transformation) { + Statement statement = allocVal.getAllocStatement(); + InvokeExpr invokeExpr = statement.getInvokeExpr(); + MethodWrapper methodWrapper = invokeExpr.getDeclaredMethod().toMethodWrapper(); + + Val base = invokeExpr.getBase(); + Val pattern = invokeExpr.getArg(0); + + Collection baseAllocSites = graph.getAllocSites(base); + Collection patternAllocSites = graph.getAllocSites(pattern); + + Collection extractedBaseValues = new HashSet<>(); + for (AllocVal baseAllocSite : baseAllocSites) { + Collection values = transformation.transformAllocationSite(baseAllocSite, graph); + extractedBaseValues.addAll(values); + } + + Collection extractedPatternValues = new HashSet<>(); + for (AllocVal patternAllocSite : patternAllocSites) { + Collection values = transformation.transformAllocationSite(patternAllocSite, graph); + extractedPatternValues.addAll(values); + } + + Collection transformedValues = new HashSet<>(); + for (TransformedValue extractedBase : extractedBaseValues) { + for (TransformedValue extractedPattern : extractedPatternValues) { + Collection knownValues = new HashSet<>(); + Collection unknownValues = new HashSet<>(); + + if (extractedBase.getTransformedVal().isStringConstant()) { + knownValues.add(extractedBase); + } else { + unknownValues.add(extractedBase); + } + + if (extractedPattern.getTransformedVal().isStringConstant()) { + knownValues.add(extractedPattern); + } else { + unknownValues.add(extractedPattern); + } + + if (!unknownValues.isEmpty()) { + // At least one variable is not a String -> Cannot evaluate 's.startsWith/endsWith(pattern)' + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } else { + // Evaluate 's.startsWith(pattern)' or 's.endsWith(pattern)' + String baseString = extractedBase.getTransformedVal().getStringValue(); + String patternString = extractedPattern.getTransformedVal().getStringValue(); + + boolean result = methodWrapper.equals(ENDS_WITH) ? + baseString.endsWith(patternString) : baseString.startsWith(patternString); + + int booleanAsInt = result ? 1 : 0; + Val intVal = frameworkHandler.createIntConstant(booleanAsInt, statement.getMethod()); + TransformedValue value = new TransformedValue(intVal, statement, knownValues); + transformedValues.add(value); + } + } + } + + return transformedValues; + } + + private Collection evaluateTrim( + AllocVal allocVal, AllocationSiteGraph graph, TransformationHandler transformation) { + Statement statement = allocVal.getAllocStatement(); + Val base = statement.getInvokeExpr().getBase(); + Collection allocSites = graph.getAllocSites(base); + + Collection extractedValues = new HashSet<>(); + for (AllocVal allocSite : allocSites) { + Collection values = transformation.transformAllocationSite(allocSite, graph); + extractedValues.addAll(values); + } + + Collection transformedValues = new HashSet<>(); + for (TransformedValue value : extractedValues) { + Val val = value.getTransformedVal(); + + if (val.isStringConstant()) { + String baseString = val.getStringValue(); + String transformedString = baseString.trim(); + + Val stringVal = frameworkHandler.createStringConstant( + transformedString, statement.getMethod()); + TransformedValue transVal = new TransformedValue(stringVal, statement, value); + transformedValues.add(transVal); + } else { + TransformedValue transVal = new TransformedValue( + allocVal.getAllocVal(), + statement, + Collections.emptySet(), + Collections.singleton(value)); + transformedValues.add(transVal); + } + } + return transformedValues; + } + private Collection evaluateSubstring( + AllocVal allocVal, AllocationSiteGraph graph, TransformationHandler transformation) { + Statement statement = allocVal.getAllocStatement(); + InvokeExpr invokeExpr = statement.getInvokeExpr(); + MethodWrapper methodWrapper = invokeExpr.getDeclaredMethod().toMethodWrapper(); + + Val base = invokeExpr.getBase(); + Val beginIndex = invokeExpr.getArg(0); + + Collection baseAllocSites = graph.getAllocSites(base); + Collection beginIndexAllocSites = graph.getAllocSites(beginIndex); + + Collection extractedBaseValues = new HashSet<>(); + for (AllocVal baseAllocSite : baseAllocSites) { + Collection values = transformation.transformAllocationSite(baseAllocSite, graph); + extractedBaseValues.addAll(values); + } + + Collection extractedBeginIndexValues = new HashSet<>(); + for (AllocVal beginIndexAllocSite : beginIndexAllocSites) { + Collection values = transformation.transformAllocationSite(beginIndexAllocSite, graph); + extractedBeginIndexValues.addAll(values); + } + + Collection transformedValues = new HashSet<>(); + + if (methodWrapper.equals(SUBSTRING_TWO_PARAMS)) { + // Handle substring(beginIndex, endIndex) + Val endIndex = invokeExpr.getArg(1); + Collection endIndexAllocSites = graph.getAllocSites(endIndex); + + Collection extractedEndIndexValues = new HashSet<>(); + for (AllocVal endIndexAllocSite : endIndexAllocSites) { + Collection values = transformation.transformAllocationSite(endIndexAllocSite, graph); + extractedEndIndexValues.addAll(values); + } + + for (TransformedValue extractedBase : extractedBaseValues) { + for (TransformedValue extractedBeginIndex : extractedBeginIndexValues) { + for (TransformedValue extractedEndIndex : extractedEndIndexValues) { + Collection knownValues = new HashSet<>(); + Collection unknownValues = new HashSet<>(); + + if (extractedBase.getTransformedVal().isStringConstant()) { + knownValues.add(extractedBase); + } else { + unknownValues.add(extractedBase); + } + + if (extractedBeginIndex.getTransformedVal().isIntConstant()) { + knownValues.add(extractedBeginIndex); + } else { + unknownValues.add(extractedBeginIndex); + } + + if (extractedEndIndex.getTransformedVal().isIntConstant()) { + knownValues.add(extractedEndIndex); + } else { + unknownValues.add(extractedEndIndex); + } + + if (!unknownValues.isEmpty()) { + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } else { + // Evaluate substring(beginIndex, endIndex) + String baseString = extractedBase.getTransformedVal().getStringValue(); + int beginIdx = extractedBeginIndex.getTransformedVal().getIntValue(); + int endIdx = extractedEndIndex.getTransformedVal().getIntValue(); + + try { + String transformedString = baseString.substring(beginIdx, endIdx); + Val stringVal = frameworkHandler.createStringConstant( + transformedString, statement.getMethod()); + TransformedValue value = new TransformedValue(stringVal, statement, knownValues); + transformedValues.add(value); + } catch (IndexOutOfBoundsException e) { + // Handle bounds error - return unknown + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } + } + } + } + } + } else { + // Handle substring(beginIndex) + for (TransformedValue extractedBase : extractedBaseValues) { + for (TransformedValue extractedBeginIndex : extractedBeginIndexValues) { + Collection knownValues = new HashSet<>(); + Collection unknownValues = new HashSet<>(); + + if (extractedBase.getTransformedVal().isStringConstant()) { + knownValues.add(extractedBase); + } else { + unknownValues.add(extractedBase); + } + + if (extractedBeginIndex.getTransformedVal().isIntConstant()) { + knownValues.add(extractedBeginIndex); + } else { + unknownValues.add(extractedBeginIndex); + } + + if (!unknownValues.isEmpty()) { + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } else { + // Evaluate substring(beginIndex) + String baseString = extractedBase.getTransformedVal().getStringValue(); + int beginIdx = extractedBeginIndex.getTransformedVal().getIntValue(); + + try { + String transformedString = baseString.substring(beginIdx); + Val stringVal = frameworkHandler.createStringConstant( + transformedString, statement.getMethod()); + TransformedValue value = new TransformedValue(stringVal, statement, knownValues); + transformedValues.add(value); + } catch (IndexOutOfBoundsException e) { + // Handle bounds error - return unknown + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } + } + } + } + } + + return transformedValues; + } + + private Collection evaluateCharAt( + AllocVal allocVal, AllocationSiteGraph graph, TransformationHandler transformation) { + Statement statement = allocVal.getAllocStatement(); + InvokeExpr invokeExpr = statement.getInvokeExpr(); + + Val base = invokeExpr.getBase(); + Val index = invokeExpr.getArg(0); + + Collection baseAllocSites = graph.getAllocSites(base); + Collection indexAllocSites = graph.getAllocSites(index); + + Collection extractedBaseValues = new HashSet<>(); + for (AllocVal baseAllocSite : baseAllocSites) { + Collection values = transformation.transformAllocationSite(baseAllocSite, graph); + extractedBaseValues.addAll(values); + } + + Collection extractedIndexValues = new HashSet<>(); + for (AllocVal indexAllocSite : indexAllocSites) { + Collection values = transformation.transformAllocationSite(indexAllocSite, graph); + extractedIndexValues.addAll(values); + } + + Collection transformedValues = new HashSet<>(); + for (TransformedValue extractedBase : extractedBaseValues) { + for (TransformedValue extractedIndex : extractedIndexValues) { + Collection knownValues = new HashSet<>(); + Collection unknownValues = new HashSet<>(); + + if (extractedBase.getTransformedVal().isStringConstant()) { + knownValues.add(extractedBase); + } else { + unknownValues.add(extractedBase); + } + + if (extractedIndex.getTransformedVal().isIntConstant()) { + knownValues.add(extractedIndex); + } else { + unknownValues.add(extractedIndex); + } + + if (!unknownValues.isEmpty()) { + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } else { + // Evaluate charAt + String baseString = extractedBase.getTransformedVal().getStringValue(); + int idx = extractedIndex.getTransformedVal().getIntValue(); + + try { + char ch = baseString.charAt(idx); + // Since FrameworkHandler doesn't have createCharConstant, convert to string + String charAsString = String.valueOf(ch); + Val stringVal = frameworkHandler.createStringConstant(charAsString, statement.getMethod()); + TransformedValue value = new TransformedValue(stringVal, statement, knownValues); + transformedValues.add(value); + } catch (IndexOutOfBoundsException e) { + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } + } + } + } + + return transformedValues; + } + + private Collection evaluateIndexOf( + AllocVal allocVal, AllocationSiteGraph graph, TransformationHandler transformation) { + Statement statement = allocVal.getAllocStatement(); + InvokeExpr invokeExpr = statement.getInvokeExpr(); + + Val base = invokeExpr.getBase(); + Val searchStr = invokeExpr.getArg(0); + + Collection baseAllocSites = graph.getAllocSites(base); + Collection searchStrAllocSites = graph.getAllocSites(searchStr); + + Collection extractedBaseValues = new HashSet<>(); + for (AllocVal baseAllocSite : baseAllocSites) { + Collection values = transformation.transformAllocationSite(baseAllocSite, graph); + extractedBaseValues.addAll(values); + } + + Collection extractedSearchValues = new HashSet<>(); + for (AllocVal searchAllocSite : searchStrAllocSites) { + Collection values = transformation.transformAllocationSite(searchAllocSite, graph); + extractedSearchValues.addAll(values); + } + + Collection transformedValues = new HashSet<>(); + for (TransformedValue extractedBase : extractedBaseValues) { + for (TransformedValue extractedSearch : extractedSearchValues) { + Collection knownValues = new HashSet<>(); + Collection unknownValues = new HashSet<>(); + + if (extractedBase.getTransformedVal().isStringConstant()) { + knownValues.add(extractedBase); + } else { + unknownValues.add(extractedBase); + } + + if (extractedSearch.getTransformedVal().isStringConstant()) { + knownValues.add(extractedSearch); + } else { + unknownValues.add(extractedSearch); + } + + if (!unknownValues.isEmpty()) { + TransformedValue value = new TransformedValue( + allocVal.getAllocVal(), statement, knownValues, unknownValues); + transformedValues.add(value); + } else { + // Evaluate indexOf + String baseString = extractedBase.getTransformedVal().getStringValue(); + String searchString = extractedSearch.getTransformedVal().getStringValue(); + + int result = baseString.indexOf(searchString); + Val intVal = frameworkHandler.createIntConstant(result, statement.getMethod()); + TransformedValue value = new TransformedValue(intVal, statement, knownValues); + transformedValues.add(value); + } + } + } + + return transformedValues; + } }