FlowDroid icon indicating copy to clipboard operation
FlowDroid copied to clipboard

A couple of questions regarding an issue running call flow analysis

Open amohar opened this issue 3 years ago • 0 comments

Hello everyone!

I'm testing the call flow generation (for starters without any taint analysis or information flow analysis, just the call flows) on the InsecureBank apk. I'm seeing some unexpected output. I've added my questions first then the relevant code snippets.

Here are my questions:

  1. The call graph for many methods is empty (my output snippet below), my guess is that it's not created as their connections to the source are not being found. If there are methods that are not connected with the source of the call graph, can I at least see them as disconnected trees? I don't want to miss any code when visualizing the application.
  2. I've heard FlowDroid has some issues with implicit calls. I've noticed the methods with the missing call flows are called from the callbacks. Could this be it? Can you give me an example of which kinds of calls would be problematic for FlowDroid to find connections between? (I know there are problems with ICC but there are some solutions for that, right? Is there anything else?)
  3. I've noticed in onCreate call (method jimple listed below) we have outgoing calls to setOnClickListener, but those calls are not displayed on the list. I'm not sure what is special for these calls to be omitted. Is there a setting that can keep them in the tree? I'd expect this would be a problem for taint analysis if any parameters in those method calls were tainted. One more question here, as they are not calling the methods directly but are actually creating callbacks, will this callback code be properly displayed as part of the tree?
  4. Lastly, am I missing any other parameters that might cut out some code so that it does not appear in the final call flow tree (or forest, if the things in question 1 can be implemented)? I can attach any files necessary.

Thanks for any information!

This is my POC app:

public static void main(String[] args)
{
  String androidJar = "android.jar";
  String apkPath = args.length == 0 ? "InsecureBank.apk" : args[0];
  InfoflowConfiguration.CallgraphAlgorithm cgAlgorithm = InfoflowConfiguration.CallgraphAlgorithm.SPARK;

  final InfoflowAndroidConfiguration config = new InfoflowAndroidConfiguration();
  config.getAnalysisFileConfig().setTargetAPKFile(apkPath);
  config.getAnalysisFileConfig().setAndroidPlatformDir(androidJar);
  config.setCodeEliminationMode(InfoflowConfiguration.CodeEliminationMode.NoCodeElimination);
  config.setCallgraphAlgorithm(cgAlgorithm);    // SPARK
  config.setIgnoreFlowsInSystemPackages(false); // Without this line the onCreate method doesn't have any entries

  SetupApplication app = new SetupApplication(config);
  app.constructCallgraph();

  CallGraph callGraph = Scene.v().getCallGraph();
  Chain<SootClass> classes = Scene.v().getClasses();
  for (SootClass cls : classes)
  {
    if (!cls.getName().startsWith("com.android.insecurebank"))
      continue;
    System.out.println(String.format("Class %s:", cls.getName()));
    for (SootMethod sootMethod : cls.getMethods())
    {
      System.out.println(String.format("\tMethod %s, Phantom: %b", sootMethod.getName(), sootMethod.isPhantom()));
      for (Edge e : iteratorToIterable(callGraph.edgesInto(sootMethod)))
      {
        System.out.println(String.format("\t\tCall graph call from: %s:%s", e.src().getDeclaringClass().getName(), e.src().getName()));
      }
      for (Edge e : iteratorToIterable(callGraph.edgesOutOf(sootMethod)))
      {
        System.out.println(String.format("\t\tCall graph call to: %s:%s", e.tgt().getDeclaringClass().getName(), e.tgt().getName()));
      }
    }
  }
}

This is the Jimple method in question 3 (class LoginScreen, method onCreate):

public void onCreate(android.os.Bundle)
{
    com.android.insecurebank.LoginScreen r0;
    android.os.Bundle $r1;
    android.view.View $r2;
    android.widget.EditText $r3;
    android.widget.Button $r4;
    com.android.insecurebank.LoginScreen$1 $r5;
    com.android.insecurebank.LoginScreen$2 $r6;
    com.android.insecurebank.LoginScreen$3 $r7;

    r0 := @this: com.android.insecurebank.LoginScreen;

    $r1 := @parameter0: android.os.Bundle;

    specialinvoke r0.<android.app.Activity: void onCreate(android.os.Bundle)>($r1);

    virtualinvoke r0.<com.android.insecurebank.LoginScreen: void setContentView(int)>(2130903041);

    $r2 = virtualinvoke r0.<com.android.insecurebank.LoginScreen: android.view.View findViewById(int)>(2131099649);

    $r3 = (android.widget.EditText) $r2;

    r0.<com.android.insecurebank.LoginScreen: android.widget.EditText Username_Text> = $r3;

    $r2 = virtualinvoke r0.<com.android.insecurebank.LoginScreen: android.view.View findViewById(int)>(2131099650);

    $r3 = (android.widget.EditText) $r2;

    r0.<com.android.insecurebank.LoginScreen: android.widget.EditText Password_Text> = $r3;

    $r2 = virtualinvoke r0.<com.android.insecurebank.LoginScreen: android.view.View findViewById(int)>(2131099652);

    $r4 = (android.widget.Button) $r2;

    r0.<com.android.insecurebank.LoginScreen: android.widget.Button Login_Button> = $r4;

    $r2 = virtualinvoke r0.<com.android.insecurebank.LoginScreen: android.view.View findViewById(int)>(2131099654);

    $r4 = (android.widget.Button) $r2;

    r0.<com.android.insecurebank.LoginScreen: android.widget.Button Preferences> = $r4;

    $r2 = virtualinvoke r0.<com.android.insecurebank.LoginScreen: android.view.View findViewById(int)>(2131099653);

    $r4 = (android.widget.Button) $r2;

    r0.<com.android.insecurebank.LoginScreen: android.widget.Button Fill_Data> = $r4;

    $r4 = r0.<com.android.insecurebank.LoginScreen: android.widget.Button Login_Button>;

    $r5 = new com.android.insecurebank.LoginScreen$1;

    specialinvoke $r5.<com.android.insecurebank.LoginScreen$1: void <init>(com.android.insecurebank.LoginScreen)>(r0);

    virtualinvoke $r4.<android.widget.Button: void setOnClickListener(android.view.View$OnClickListener)>($r5);

    $r4 = r0.<com.android.insecurebank.LoginScreen: android.widget.Button Fill_Data>;

    $r6 = new com.android.insecurebank.LoginScreen$2;

    specialinvoke $r6.<com.android.insecurebank.LoginScreen$2: void <init>(com.android.insecurebank.LoginScreen)>(r0);

    virtualinvoke $r4.<android.widget.Button: void setOnClickListener(android.view.View$OnClickListener)>($r6);

    $r4 = r0.<com.android.insecurebank.LoginScreen: android.widget.Button Preferences>;

    $r7 = new com.android.insecurebank.LoginScreen$3;

    specialinvoke $r7.<com.android.insecurebank.LoginScreen$3: void <init>(com.android.insecurebank.LoginScreen)>(r0);

    virtualinvoke $r4.<android.widget.Button: void setOnClickListener(android.view.View$OnClickListener)>($r7);

    return;
}

This is the output I'm seeing:

Class com.android.insecurebank.LoginScreen:
        Method <init>, Phantom: false
                Call graph call from: dummyMainClass:dummyMainMethod_com_android_insecurebank_LoginScreen
                Call graph call to: android.app.Activity:<init>
        Method access$0, Phantom: false
        Method access$1, Phantom: false
        Method dologin, Phantom: false
        Method fill_data, Phantom: false
        Method onCreate, Phantom: false
                Call graph call from: dummyMainClass:dummyMainMethod_com_android_insecurebank_LoginScreen
                Call graph call to: com.android.insecurebank.LoginScreen$3:<init>
                Call graph call to: android.app.Activity:findViewById
                Call graph call to: android.app.Activity:findViewById
                Call graph call to: android.app.Activity:findViewById
                Call graph call to: android.app.Activity:findViewById
                Call graph call to: android.app.Activity:findViewById
                Call graph call to: android.app.Activity:setContentView
                Call graph call to: android.app.Activity:onCreate
                Call graph call to: com.android.insecurebank.LoginScreen$1:<init>
                Call graph call to: com.android.insecurebank.LoginScreen$2:<init>
        Method rememberme, Phantom: false
        Method setpref, Phantom: false
        Method getIntent, Phantom: false
        Method setIntent, Phantom: false
        Method setResult, Phantom: false

EDIT: Uh, only now I've realised this might be similar to #335 but it doesn't have any answers yet, too.

amohar avatar Apr 21 '21 17:04 amohar