Skip to content

Commit

Permalink
Merge pull request #8 from noidsirius/CGPTA_Tutorial
Browse files Browse the repository at this point in the history
CallGraph and PointsTo Analysis tutorial
  • Loading branch information
noidsirius authored Mar 19, 2021
2 parents 4182739 + 7263353 commit abb6d4e
Show file tree
Hide file tree
Showing 44 changed files with 948 additions and 38 deletions.
69 changes: 42 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,48 +11,48 @@ Anybody who knows Java programming and wants to do some static analysis in pract

If you have some prior knowledge about static program analysis I suggest you learn Soot from [here](https://github.com/Sable/soot/wiki/Tutorials).

### [Why another tutorial for Soot?](https://github.com/noidsirius/SootTutorial/blob/master/docs/Other/Motivation.md)
### [Why another tutorial for Soot?](docs/Other/Motivation.md)

## Setup
In short, use Java 8 and run `./gradlew build`. For more information and Docker setup, follow this [link](https://github.com/noidsirius/SootTutorial/blob/master/docs/Setup/).
In short, use Java 8 and run `./gradlew build`. For more information and Docker setup, follow this [link](docs/Setup/).



## Chapters
### 1: Get your hands dirty

In this chapter, you will visit a very simple code example to be familiar with Soot essential data structures and **Jimple**, Soot's principle intermediate representation.

* `./gradlew run --args="HelloSoot"`: The Jimple representation of the [printFizzBuzz](https://github.com/noidsirius/SootTutorial/tree/master/demo/HelloSoot/FizzBuzz.java) method alongside the branch statement.
* `./gradlew run --args="HelloSoot draw"`: The visualization of the [printFizzBuzz](https://github.com/noidsirius/SootTutorial/tree/master/demo/HelloSoot/FizzBuzz.java) control-flow graph.
* `./gradlew run --args="HelloSoot"`: The Jimple representation of the [printFizzBuzz](demo/HelloSoot/FizzBuzz.java) method alongside the branch statement.
* `./gradlew run --args="HelloSoot draw"`: The visualization of the [printFizzBuzz](demo/HelloSoot/FizzBuzz.java) control-flow graph.



|Title |Tutorial | Soot Code | Example Input |
| :---: |:-------------: |:-------------:| :-----:|
|Hello Soot |[Doc](https://github.com/noidsirius/SootTutorial/blob/master/docs/1/) | [HelloSoot.java](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/hellosoot/HelloSoot.java) | [FizzBuzz.java](https://github.com/noidsirius/SootTutorial/tree/master/demo/HelloSoot/FizzBuzz.java) |
|Hello Soot |[Doc](docs/1/) | [HelloSoot.java](src/main/java/dev/navids/soottutorial/hellosoot/HelloSoot.java) | [FizzBuzz.java](demo/HelloSoot/FizzBuzz.java) |

<img src="https://github.com/noidsirius/SootTutorial/blob/master/docs/1/images/cfg.png" alt="Control Flow Graph" width="400"/>
<img src="docs/1/images/cfg.png" alt="Control Flow Graph" width="400"/>

### 2: Know the basic APIs

In this chapter, you get familiar with some basic but useful methods in Soot to help read, analyze, and even update java code.

* `./gradlew run --args="BasicAPI"`: Analyze the class [Circle](https://github.com/noidsirius/SootTutorial/tree/master/demo/BasicAPI/Circle.java).
* `./gradlew run --args="BasicAPI draw"`: Analyze the class [Circle](https://github.com/noidsirius/SootTutorial/tree/master/demo/BasicAPI/Circle.java) and draws the call graph.
* `./gradlew run --args="BasicAPI"`: Analyze the class [Circle](demo/BasicAPI/Circle.java).
* `./gradlew run --args="BasicAPI draw"`: Analyze the class [Circle](demo/BasicAPI/Circle.java) and draws the call graph.

|Title |Tutorial | Soot Code | Example Input |
| :---: |:-------------: |:-------------:| :-----:|
|Basic API |[Doc](https://medium.com/@noidsirius/know-the-basic-tools-in-soot-18f394318a9c)| [BasicAPI.java](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/basicapi/BasicAPI.java) | [Circle](https://github.com/noidsirius/SootTutorial/tree/master/demo/BasicAPI/Circle.java) |
|Basic API |[Doc](https://medium.com/@noidsirius/know-the-basic-tools-in-soot-18f394318a9c)| [BasicAPI.java](src/main/java/dev/navids/soottutorial/basicapi/BasicAPI.java) | [Circle](demo/BasicAPI/Circle.java) |


<img src="https://github.com/noidsirius/SootTutorial/blob/master/docs/2/images/callgraph.png" alt="Call Graph" width="400"/>
<img src="docs/2/images/callgraph.png" alt="Call Graph" width="400"/>

### 3: Android Instrumentation

In this chapter, you learn how to insert code into Android apps (without having their source code) using Soot. To run the code, you need Android SDK (check this [link](https://github.com/noidsirius/SootTutorial/blob/master/docs/Setup/)).
In this chapter, you learn how to insert code into Android apps (without having their source code) using Soot. To run the code, you need Android SDK (check this [link](docs/Setup/)).

* `./gradlew run --args="AndroidLogger"`: Insert logging method calls at the beginning of APK methods of [Numix Calculator](https://github.com/noidsirius/SootTutorial/tree/master/demo/Android/calc.apk).
* `./gradlew run --args="AndroidClassInjector"`: Create a new class from scratch and inject it to the [Numix Calculator](https://github.com/noidsirius/SootTutorial/tree/master/demo/Android/calc.apk).
* `./gradlew run --args="AndroidLogger"`: Insert logging method calls at the beginning of APK methods of [Numix Calculator](demo/Android/calc.apk).
* `./gradlew run --args="AndroidClassInjector"`: Create a new class from scratch and inject it to the [Numix Calculator](demo/Android/calc.apk).

The instrumented APK is located in `demo/Android/Instrumented`. You need to sign it in order to install on an Android device:
```aidl
Expand All @@ -64,27 +64,42 @@ To see the logs, run `adb logcat | grep -e "<SOOT_TUTORIAL>"`

|Title |Tutorial | Soot Code | Example APK|
| :---: |:-------------: |:-------------:| :-----:|
|Log method calls in an APK| [Doc](https://medium.com/@noidsirius/instrumenting-android-apps-with-soot-dd6f146ff4d2)| [AndroidLogger.java](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/android/AndroidLogger.java) | [Numix Calculator](https://github.com/noidsirius/SootTutorial/tree/master/demo/Android/calc.apk) (from [F-Droid](https://f-droid.org/en/packages/com.numix.calculator/))|
|Create and inject a class into an APK| [Doc](https://medium.com/@noidsirius/instrumenting-android-apps-with-soot-dd6f146ff4d2) | [AndroidClassInjector.java](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/android/AndroidClassInjector.java) | [Numix Calculator](https://github.com/noidsirius/SootTutorial/tree/master/demo/Android/calc.apk) (from [F-Droid](https://f-droid.org/en/packages/com.numix.calculator/))|
|Log method calls in an APK| [Doc](https://medium.com/@noidsirius/instrumenting-android-apps-with-soot-dd6f146ff4d2)| [AndroidLogger.java](src/main/java/dev/navids/soottutorial/android/AndroidLogger.java) | [Numix Calculator](demo/Android/calc.apk) (from [F-Droid](https://f-droid.org/en/packages/com.numix.calculator/))|
|Create and inject a class into an APK| [Doc](https://medium.com/@noidsirius/instrumenting-android-apps-with-soot-dd6f146ff4d2) | [AndroidClassInjector.java](src/main/java/dev/navids/soottutorial/android/AndroidClassInjector.java) | [Numix Calculator](demo/Android/calc.apk) (from [F-Droid](https://f-droid.org/en/packages/com.numix.calculator/))|

<img src="https://github.com/noidsirius/SootTutorial/blob/master/docs/3/images/packs.png" alt="Soot Packs + Dexpler" width="400"/>
<img src="docs/3/images/packs.png" alt="Soot Packs + Dexpler" width="400"/>

### 4: Some *Real* Static Analysis (:construction: WIP)
### 4: Call graphs and PointsTo Analysis in Android

* `./gradlew run --args="UsageFinder 'void println(java.lang.String)' 'java.io.PrintStream"`: Find usages of the method with the given subsignature in all methods of [UsageExample.java](https://github.com/noidsirius/SootTutorial/tree/master/demo/IntraAnalysis/UsageExample.java).
* `./gradlew run --args="UsageFinder 'void println(java.lang.String)' 'java.io.PrintStream"`: Find usages of the method with the given subsignature of the given class signature in all methods of [UsageExample.java](https://github.com/noidsirius/SootTutorial/tree/master/demo/IntraAnalysis/UsageExample.java).
This chapter gives you a brief overview o call graphs and PointsTo analysis in Android and you learn how to create calls graphs using FlowDroid. The source code of the example code is [here](demo/Android/STDemoApp). To run the code, you need Android SDK (check this [link](docs/Setup/)).

* `./gradlew run --args="AndroidCallGraph <CG_Algorithm> (draw)"`: Create the call graph of [SootTutorial Demo App](demo/Android/st_demo.apk) using `<CG_Algorithm>` algorithm and print information such as reachable methods or the number of edges.
* `<CG_Algorithm>` can be `SPARK` or `CHA`
* `draw` argument is optional, if provided a visualization of call graph will shown.
* For example, `./gradlew run --args="AndroidCallGraph SPARK draw"` visualizes the call graph generated by SPARK algorithm.
* `./gradlew run --args="AndroidPTA"`: Perform PointsTo and Alias Analysis on [SootTutorial Demo App](demo/Android/st_demo.apk) using FlowDroid.

|Title |Tutorial | Soot Code | Example Input |
|Title |Tutorial | Soot Code | Example APK|
| :---: |:-------------: |:-------------:| :-----:|
|Find usages of a method| | [UsageFinder.java](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/intraanalysis/usagefinder/UsageFinder.java) | [UsageExample.java](https://github.com/noidsirius/SootTutorial/tree/master/demo/IntraAnalysis/usagefinder/UsageExample.java) |
|Null Pointer Analysis ||[NullPointerAnalysis](https://github.com/noidsirius/SootTutorial/tree/master/src/main/java/dev/navids/soottutorial/intraanalysis/npanalysis/) | [NullPointerExample.java](https://github.com/noidsirius/SootTutorial/tree/master/demo/IntraAnalysis/NullPointerExample.java) |
|Call graphs in Android| [Doc](https://medium.com/geekculture/generating-call-graphs-in-android-using-flowdroid-pointsto-analysis-7b2e296e6697)| [AndroidCallgraph.java](src/main/java/dev/navids/soottutorial/android/AndroidCallgraph.java) | [SootTutorial Demo App](demo/Android/st_demo.apk) ([source code](demo/Android/STDemoApp))|
|PointsTo Analysis in Android| [Doc](https://medium.com/geekculture/generating-call-graphs-in-android-using-flowdroid-pointsto-analysis-7b2e296e6697)| [AndroidPointsToAnalysis.java](src/main/java/dev/navids/soottutorial/android/AndroidPointsToAnalysis.java) | [SootTutorial Demo App](demo/Android/st_demo.apk) ([source code](demo/Android/STDemoApp))|

<img src="docs/4/images/Spark_CG.png" alt="The call graph of SootTutorial Demo app" width="400"/>



### 5: Some *Real* Static Analysis (:construction: WIP)

* `./gradlew run --args="UsageFinder 'void println(java.lang.String)' 'java.io.PrintStream"`: Find usages of the method with the given subsignature in all methods of [UsageExample.java](demo/IntraAnalysis/UsageExample.java).
* `./gradlew run --args="UsageFinder 'void println(java.lang.String)' 'java.io.PrintStream"`: Find usages of the method with the given subsignature of the given class signature in all methods of [UsageExample.java](demo/IntraAnalysis/UsageExample.java).


### 5: Manipulate the code (:construction: WIP)
### 6: Call Graphs (:construction: WIP)
### 7: Interprocedural analysis (:construction: WIP)
|Title |Tutorial | Soot Code | Example Input |
| :---: |:-------------: |:-------------:| :-----:|
| | | | |
|Find usages of a method| | [UsageFinder.java](src/main/java/dev/navids/soottutorial/intraanalysis/usagefinder/UsageFinder.java) | [UsageExample.java](demo/IntraAnalysis/usagefinder/UsageExample.java) |
|Null Pointer Analysis ||[NullPointerAnalysis](src/main/java/dev/navids/soottutorial/intraanalysis/npanalysis/) | [NullPointerExample.java](demo/IntraAnalysis/NullPointerExample.java) |

### 6: Interprocedural analysis (:construction: WIP)
|Title |Tutorial | Soot Code | Example Input |
| :---: |:-------------: |:-------------:| :-----:|
| | | | |
14 changes: 14 additions & 0 deletions demo/Android/STDemoApp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
.cxx
1 change: 1 addition & 0 deletions demo/Android/STDemoApp/app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
29 changes: 29 additions & 0 deletions demo/Android/STDemoApp/app/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 29
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "dev.navids.multicomp1"
minSdkVersion 14
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
}
21 changes: 21 additions & 0 deletions demo/Android/STDemoApp/app/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package dev.navids.multicomp1;

import android.content.Context;

import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();

assertEquals("dev.navids.multicomp1", appContext.getPackageName());
}
}
36 changes: 36 additions & 0 deletions demo/Android/STDemoApp/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="dev.navids.multicomp1">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF" />
</intent-filter>
</receiver>

<activity
android:name=".SecondActivity"
android:excludeFromRecents="true"
android:theme="@style/Theme.AppCompat.Dialog" />
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package dev.navids.multicomp1;

public class ClassChild extends ClassParent {
@Override
public void baseMethod(){
childMethod();
}

public void childMethod(){
System.out.println("In child");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package dev.navids.multicomp1;

public class ClassParent {
public void baseMethod(){}

public void unreachableMethod(){
System.out.println("Nobody calls me");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package dev.navids.multicomp1;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

ClassParent childInstance = new ClassChild();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.second_act_button).setOnClickListener(new Button1());
findViewById(R.id.dialog_button).setOnClickListener( new Button2());
}

class Button1 implements View.OnClickListener{
@Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, SecondActivity.class);
startActivity(intent);
}
}

class Button2 implements View.OnClickListener{
class Dialogue1 implements DialogInterface.OnClickListener{
ClassChild childInstance = new ClassChild();
@Override
public void onClick(DialogInterface dialog, int which) {
childInstance.baseMethod();
}
}
@Override
public void onClick(View v) {
new AlertDialog.Builder(MainActivity.this)
.setTitle("A dialog")
.setMessage("Call 'baseMethod' through ClassChild?")
.setPositiveButton(android.R.string.yes, new Dialogue1())
.setNegativeButton(android.R.string.no, null)
.setIcon(android.R.drawable.ic_dialog_alert)
.show();
}
}

@Override
protected void onResume() {
super.onResume();
}

@Override
protected void onStart() {
super.onStart();
childInstance.baseMethod();
System.out.println("---- onStart");
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package dev.navids.multicomp1;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MyReceiver extends BroadcastReceiver {
// ClassA instanceA = new ClassA();
ClassParent instanceFromSecondActivity;
public MyReceiver() {
instanceFromSecondActivity = SecondActivity.parentInstance;
}

@Override
public void onReceive(Context context, Intent intent) {
intermediaryMethod();
new ClassParent().baseMethod();
System.out.println("---- Receive something");
}

public void intermediaryMethod(){
instanceFromSecondActivity.baseMethod();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package dev.navids.multicomp1;

import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;

import androidx.appcompat.app.AppCompatActivity;

public class SecondActivity extends AppCompatActivity {

MyReceiver myReceiver = new MyReceiver();
static ClassParent parentInstance = new ClassParent();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
parentInstance.baseMethod();
setContentView(R.layout.activity_main2);
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(myReceiver, intentFilter);
findViewById(R.id.use_button).setOnClickListener(new Button3());
}
class Button3 implements View.OnClickListener{
ClassChild childInstance = new ClassChild();
@Override
public void onClick(View v) {
childInstance.baseMethod();
}
}
}
Loading

0 comments on commit abb6d4e

Please sign in to comment.