├── packages.txt
├── helper
├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── themes.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── layout
│ │ │ │ │ └── activity_main.xml
│ │ │ │ ├── values-night
│ │ │ │ │ └── themes.xml
│ │ │ │ ├── drawable-v24
│ │ │ │ │ └── ic_launcher_foreground.xml
│ │ │ │ └── drawable
│ │ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── research
│ │ │ │ │ └── helper
│ │ │ │ │ ├── MainActivity.kt
│ │ │ │ │ ├── AutoStart.kt
│ │ │ │ │ └── SendGPS.kt
│ │ │ └── AndroidManifest.xml
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── com
│ │ │ │ └── research
│ │ │ │ └── helper
│ │ │ │ └── ExampleUnitTest.kt
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── com
│ │ │ └── research
│ │ │ └── helper
│ │ │ └── ExampleInstrumentedTest.kt
│ ├── proguard-rules.pro
│ └── build.gradle
├── .idea
│ ├── .gitignore
│ ├── compiler.xml
│ ├── misc.xml
│ └── gradle.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
├── build.gradle
├── gradle.properties
├── gradlew.bat
└── gradlew
├── requirements.txt
├── exceptions.py
├── timeout.py
├── Readme.md
├── interactor_parameters.json
├── js
├── debug.js
├── fs.js
├── media.js
├── bypass_root_detection.js
├── general.js
├── native.js
├── built_in_crypto.js
├── java.js
└── pinning.js
├── amplification.py
├── static.py
├── main.py
├── dynamic.py
├── device.py
└── interactor.py
/packages.txt:
--------------------------------------------------------------------------------
1 | pkg.name
--------------------------------------------------------------------------------
/helper/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/helper/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/helper/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | helper
3 |
--------------------------------------------------------------------------------
/helper/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | androidviewclient
2 | uiautomator
3 | translators==5.4.2
4 | androguard==3.4.0a1
5 | frida
6 | frida-tools
7 | mitmproxy
8 | xmltodict
9 | dpkt
10 |
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Madiba-Research/ThirdEye/HEAD/helper/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/helper/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/helper/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 16 01:45:11 EDT 2021
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/helper/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/exceptions.py:
--------------------------------------------------------------------------------
1 | class DeviceNotFound(Exception):
2 | # def __init__(self, salary=12, message="Salary is not in (5000, 15000) range"):
3 | # self.salary = salary
4 | # self.message = message
5 | # super().__init__(self.message)
6 |
7 | def __str__(self):
8 | return 'no devices/emulators found'
9 |
10 |
--------------------------------------------------------------------------------
/helper/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/helper/settings.gradle:
--------------------------------------------------------------------------------
1 | dependencyResolutionManagement {
2 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
3 | repositories {
4 | google()
5 | mavenCentral()
6 | jcenter() // Warning: this repository is going to shut down soon
7 | }
8 | }
9 | rootProject.name = "helper"
10 | include ':app'
11 |
--------------------------------------------------------------------------------
/helper/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/helper/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/helper/app/src/test/java/com/research/helper/ExampleUnitTest.kt:
--------------------------------------------------------------------------------
1 | package com.research.helper
2 |
3 | import org.junit.Test
4 |
5 | import org.junit.Assert.*
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * See [testing documentation](http://d.android.com/tools/testing).
11 | */
12 | class ExampleUnitTest {
13 | @Test
14 | fun addition_isCorrect() {
15 | assertEquals(4, 2 + 2)
16 | }
17 | }
--------------------------------------------------------------------------------
/helper/app/src/main/java/com/research/helper/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package com.research.helper
2 |
3 | import android.content.Intent
4 | import androidx.appcompat.app.AppCompatActivity
5 | import android.os.Bundle
6 |
7 | class MainActivity : AppCompatActivity() {
8 | override fun onCreate(savedInstanceState: Bundle?) {
9 | super.onCreate(savedInstanceState)
10 | // val number5 = Intent(baseContext, HelperService::class.java)
11 | // number5.putExtra("times", 5)
12 | // startForegroundService(number5)
13 | finish()
14 | }
15 | }
--------------------------------------------------------------------------------
/timeout.py:
--------------------------------------------------------------------------------
1 | import signal
2 | import traceback
3 |
4 | class timeout:
5 | def __init__(self, seconds=1, error_message="Timeout"):
6 | self.seconds = seconds
7 | self.error_message = error_message
8 |
9 | def handle_timeout(self, signum, frame):
10 | traceback.print_exc()
11 | raise TimeoutError(self.error_message)
12 |
13 | def __enter__(self):
14 | signal.signal(signal.SIGALRM, self.handle_timeout)
15 | signal.alarm(self.seconds)
16 |
17 | def __exit__(self, type, value, traceback):
18 | signal.alarm(0)
19 |
--------------------------------------------------------------------------------
/helper/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 | dependencies {
8 | classpath "com.android.tools.build:gradle:7.0.2"
9 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.31"
10 |
11 | // NOTE: Do not place your application dependencies here; they belong
12 | // in the individual module build.gradle files
13 | }
14 | }
15 |
16 | task clean(type: Delete) {
17 | delete rootProject.buildDir
18 | }
--------------------------------------------------------------------------------
/helper/app/src/androidTest/java/com/research/helper/ExampleInstrumentedTest.kt:
--------------------------------------------------------------------------------
1 | package com.research.helper
2 |
3 | import androidx.test.platform.app.InstrumentationRegistry
4 | import androidx.test.ext.junit.runners.AndroidJUnit4
5 |
6 | import org.junit.Test
7 | import org.junit.runner.RunWith
8 |
9 | import org.junit.Assert.*
10 |
11 | /**
12 | * Instrumented test, which will execute on an Android device.
13 | *
14 | * See [testing documentation](http://d.android.com/tools/testing).
15 | */
16 | @RunWith(AndroidJUnit4::class)
17 | class ExampleInstrumentedTest {
18 | @Test
19 | fun useAppContext() {
20 | // Context of the app under test.
21 | val appContext = InstrumentationRegistry.getInstrumentation().targetContext
22 | assertEquals("com.research.helper", appContext.packageName)
23 | }
24 | }
--------------------------------------------------------------------------------
/helper/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
19 |
20 |
--------------------------------------------------------------------------------
/helper/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/helper/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
--------------------------------------------------------------------------------
/helper/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/helper/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 | **Implementation of CCS'2022 paper "Hidden in Plain Sight: Exploring Encrypted Channels in Android Apps"**
2 |
3 | - For inspiration only: This tool is not ready to use out of the box and requires some modification.
4 | - It mainly requires modification of the device.py file. Primarily, focus on the window and activity.
5 | - There are no plans to maintain, develop, or provide support for this tool.
6 | -----
7 | ```
8 | flame:/ # mkdir /data/crontab
9 | flame:/ # echo '* * * * * svc wifi enable' >> /data/crontab/root
10 | flame:/ # echo '* * * * * settings put global airplane_mode_on 0' >> /data/crontab/root
11 | flame:/ # echo 'crond -b -c /data/crontab' > /data/adb/service.d/crond.sh
12 | flame:/ # chmod +x /data/adb/service.d/crond.sh
13 | settings put global captive_portal_mode 0
14 |
15 | adb shell content insert --uri content://settings/system --bind name:s:accelerometer_rotation --bind value:i:0
16 | ```
17 |
--------------------------------------------------------------------------------
/helper/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
20 | # Kotlin code style for this project: "official" or "obsolete":
21 | kotlin.code.style=official
--------------------------------------------------------------------------------
/helper/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | id 'kotlin-android'
4 | }
5 |
6 | android {
7 | compileSdk 31
8 |
9 | defaultConfig {
10 | applicationId "com.research.helper"
11 | minSdk 29
12 | targetSdk 31
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 | kotlinOptions {
30 | jvmTarget = '1.8'
31 | }
32 | }
33 |
34 | dependencies {
35 |
36 | implementation 'androidx.core:core-ktx:1.3.2'
37 | implementation 'androidx.appcompat:appcompat:1.2.0'
38 | implementation 'com.google.android.material:material:1.3.0'
39 | implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
40 | testImplementation 'junit:junit:4.+'
41 | androidTestImplementation 'androidx.test.ext:junit:1.1.2'
42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
43 | }
--------------------------------------------------------------------------------
/helper/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
17 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/helper/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/helper/app/src/main/java/com/research/helper/AutoStart.kt:
--------------------------------------------------------------------------------
1 | package com.research.helper
2 |
3 |
4 | import android.content.Intent
5 |
6 | import android.content.BroadcastReceiver
7 | import android.content.Context
8 | import android.util.Log
9 | import java.lang.String
10 | import android.location.LocationManager
11 | import android.location.Location
12 | import android.os.SystemClock
13 |
14 |
15 | class AutoStart : BroadcastReceiver() {
16 | override fun onReceive(context: Context, arg1: Intent) {
17 | var lat = 45.4950378
18 | var lon = -73.5779508
19 | var alt = 5.0
20 | var accurate = 0.5f
21 | Log.i(
22 | "logTag",
23 | String.format(
24 | "setting mock to Latitude=%f, Longitude=%f Altitude=%f Accuracy=%f",
25 | lat,
26 | lon,
27 | alt,
28 | accurate
29 | )
30 | )
31 |
32 | setLocation(LocationManager.GPS_PROVIDER, context, lat, lon, alt, accurate)
33 | setLocation(LocationManager.NETWORK_PROVIDER, context, lat, lon, alt, accurate)
34 |
35 |
36 | }
37 |
38 | fun setLocation(
39 | provider: kotlin.String,
40 | context: Context,
41 | lat: Double,
42 | lon: Double,
43 | alt: Double,
44 | accuracy: Float
45 | ) {
46 | var lm = context.getSystemService(
47 | Context.LOCATION_SERVICE
48 | ) as LocationManager
49 | lm.addTestProvider(
50 | provider, false, false, false, false, false,
51 | true, true, 1, 1
52 | )
53 | val mockLocation = Location(provider)
54 | mockLocation.latitude = lat
55 | mockLocation.longitude = lon
56 | mockLocation.altitude = alt
57 | mockLocation.time = System.currentTimeMillis()
58 | mockLocation.accuracy = accuracy
59 | mockLocation.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
60 | lm.setTestProviderEnabled(provider, true)
61 | lm.setTestProviderLocation(provider, mockLocation)
62 | }
63 | }
64 |
65 |
--------------------------------------------------------------------------------
/interactor_parameters.json:
--------------------------------------------------------------------------------
1 | {
2 | "keywords": {
3 | "none of the above": [],
4 | "not now": [],
5 | "get code": [],
6 | "approv": [],
7 | "509-6730": [],
8 | "read": ["already"],
9 | "scan": [],
10 | "resend": [],
11 | "woman": [],
12 | "women": [],
13 | "female": [],
14 | "global": [],
15 | "sajjad": [],
16 | "country": [],
17 | "canada": [],
18 | "quebec": [],
19 | "18": [],
20 | "skip": [],
21 | "gmail.com": [],
22 | "start": [
23 | "startup"
24 | ],
25 | "agree": [
26 | "disagree","agreement"
27 | ],
28 | "next": [],
29 | "allow": [
30 | "disallow"
31 | ],
32 | "continue": [
33 | "continue with"
34 | ],
35 | "confirm": [],
36 | "accept": [
37 | "not accept"
38 | ],
39 | "checkbox": [],
40 | "without": [],
41 | "google": ["share"],
42 | "register": [],
43 | "sign": [
44 | "help",
45 | "can"
46 | ],
47 | "login": [
48 | "help",
49 | "can",
50 | "facebook",
51 | "google"
52 | ],
53 | "log in": [
54 | "help",
55 | "can",
56 | "facebook",
57 | "google"
58 | ],
59 | "sign in": [
60 | "help",
61 | "can",
62 | "facebook",
63 | "google"
64 | ],
65 | "enable": [],
66 | "submit": [],
67 | "retry": [],
68 | "again": [],
69 | "current": [],
70 | "i don": [],
71 | "find": [],
72 | "guest": [],
73 | "ok": [
74 | "facebook",
75 | "book"
76 | ],
77 | "test": [],
78 | "done": [],
79 | "use": [
80 | "user"
81 | ],
82 | "go": [
83 | "forgot",
84 | "good",
85 | "google"
86 | ],
87 | "an account": [],
88 | "later": [],
89 | "comment": [],
90 | "quick": [],
91 | "close": [],
92 | "send": [],
93 | "english": [],
94 | "dismiss": [],
95 | "cancel": [],
96 | "great": [],
97 | "navigation": [],
98 | "settings": [],
99 | "free": [],
100 | "limit": [],
101 | "tap": [],
102 | "click": [],
103 | "icon": []
104 | },
105 | "input": {
106 | "username": "admin88888888",
107 | "email": "ev010.173@gmail.com",
108 | "e-mail": "ev010.173@gmail.com",
109 | "name": "admin88888888",
110 | "mobile number": "+888888888888",
111 | "phone number": "9158888888",
112 | "phone": "9158888888",
113 | "password": "P4ss@88888888",
114 | "code": "9188",
115 | "pin": "1370",
116 | "city": "Montreal",
117 | "id": "9188888888",
118 | "How old": "45",
119 | "YYYY": "1991",
120 | "search": "search88888888"
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/js/debug.js:
--------------------------------------------------------------------------------
1 | setTimeout(function () {
2 | Java.perform(function () {
3 | var androidSettings = ['adb_enabled'];
4 | var settingGlobal = Java.use('android.provider.Settings$Global');
5 |
6 | settingGlobal.getInt.overload('android.content.ContentResolver', 'java.lang.String').implementation = function (cr, name) {
7 | if (name == androidSettings[0]) {
8 | return 0;
9 | }
10 | var ret = this.getInt(cr, name);
11 | return ret;
12 | }
13 |
14 | settingGlobal.getInt.overload('android.content.ContentResolver', 'java.lang.String', 'int').implementation = function (cr, name, def) {
15 | if (name == (androidSettings[0])) {
16 | return 0;
17 | }
18 | var ret = this.getInt(cr, name, def);
19 | return ret;
20 | }
21 |
22 | settingGlobal.getFloat.overload('android.content.ContentResolver', 'java.lang.String').implementation = function (cr, name) {
23 | if (name == androidSettings[0]) {
24 | return 0;
25 | }
26 | var ret = this.getFloat(cr, name);
27 | return ret;
28 | }
29 |
30 | settingGlobal.getFloat.overload('android.content.ContentResolver', 'java.lang.String', 'float').implementation = function (cr, name, def) {
31 | if (name == androidSettings[0]) {
32 | return 0;
33 | }
34 | var ret = this.getFloat(cr, name, def);
35 | return ret;
36 | }
37 |
38 | settingGlobal.getLong.overload('android.content.ContentResolver', 'java.lang.String').implementation = function (cr, name) {
39 | if (name == androidSettings[0]) {
40 | return 0;
41 | }
42 | var ret = this.getLong(cr, name);
43 | return ret;
44 | }
45 |
46 | settingGlobal.getLong.overload('android.content.ContentResolver', 'java.lang.String', 'long').implementation = function (cr, name, def) {
47 | if (name == androidSettings[0]) {
48 | return 0;
49 | }
50 | var ret = this.getLong(cr, name, def);
51 | return ret;
52 | }
53 |
54 | settingGlobal.getString.overload('android.content.ContentResolver', 'java.lang.String').implementation = function (cr, name) {
55 | if (name == androidSettings[0]) {
56 | var stringClass = Java.use("java.lang.String");
57 | var stringInstance = stringClass.$new("0");
58 |
59 | console.log('[+]Global.getString(cr, name) Bypassed');
60 | return stringInstance;
61 | }
62 | var ret = this.getString(cr, name);
63 | return ret;
64 | }
65 |
66 | });
67 | }, 0);
68 |
--------------------------------------------------------------------------------
/helper/app/src/main/java/com/research/helper/SendGPS.kt:
--------------------------------------------------------------------------------
1 | package com.research.helper
2 |
3 | import android.content.Intent
4 |
5 | import android.content.BroadcastReceiver
6 | import android.content.Context
7 | import android.util.Log
8 | import java.lang.String
9 | import android.location.LocationManager
10 | import android.location.Location
11 | import android.os.Build
12 | import android.os.SystemClock
13 |
14 |
15 | class SendGPS : BroadcastReceiver() {
16 | override fun onReceive(context: Context, intent: Intent) {
17 |
18 | Log.i("research", intent.action.toString())
19 |
20 | var lat =
21 | if (intent.getStringExtra("lat") != null) intent.getStringExtra("lat")!!
22 | .toDouble() else "0".toDouble()
23 | var lon =
24 | if (intent.getStringExtra("lon") != null) intent.getStringExtra("lon")!!
25 | .toDouble() else "0".toDouble()
26 | var alt =
27 | if (intent.getStringExtra("alt") != null) intent.getStringExtra("alt")!!
28 | .toDouble() else "0".toDouble()
29 | var accurate =
30 | if (intent.getStringExtra("accurate") != null) intent.getStringExtra("accurate")!!
31 | .toFloat() else "0".toFloat()
32 | Log.i(
33 | "logTag",
34 | String.format(
35 | "setting mock to Latitude=%f, Longitude=%f Altitude=%f Accuracy=%f",
36 | lat,
37 | lon,
38 | alt,
39 | accurate
40 | )
41 | )
42 |
43 | setLocation(LocationManager.GPS_PROVIDER, context, lat, lon, alt, accurate)
44 | setLocation(LocationManager.NETWORK_PROVIDER, context, lat, lon, alt, accurate)
45 | // val intent = Intent(context, HelperService::class.java)
46 | // context.startForegroundService(intent)
47 |
48 | }
49 |
50 |
51 | fun setLocation(
52 | provider: kotlin.String,
53 | context: Context,
54 | lat: Double,
55 | lon: Double,
56 | alt: Double,
57 | accuracy: Float
58 | ) {
59 | var lm = context.getSystemService(
60 | Context.LOCATION_SERVICE
61 | ) as LocationManager
62 | lm.addTestProvider(
63 | provider, false, false, false, false, false,
64 | true, true, 1, 1
65 | )
66 | val mockLocation = Location(provider)
67 | mockLocation.latitude = lat
68 | mockLocation.longitude = lon
69 | mockLocation.altitude = alt
70 | mockLocation.time = System.currentTimeMillis()
71 | mockLocation.accuracy = accuracy
72 | mockLocation.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos()
73 | lm.setTestProviderEnabled(provider, true)
74 | lm.setTestProviderLocation(provider, mockLocation)
75 | }
76 | }
--------------------------------------------------------------------------------
/helper/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/js/fs.js:
--------------------------------------------------------------------------------
1 |
2 | Interceptor.attach(Module.findExportByName("libc.so", "open"), {
3 | onEnter: function (args) {
4 | //console.log("Hi:"+args[0].readUtf8String())
5 | this.name = args[0].readUtf8String();
6 | this.flag = parseInt(args[1]);
7 | if (this.name.startsWith("/storage") && !this.name.startsWith("/storage/emulated/0/Android/obb") && !this.name.startsWith("/storage/emulated/0/Android/data")) {
8 |
9 | console.log("--->" + this.name);
10 | }
11 | },
12 | onLeave(retval) {
13 | if (this.name.startsWith("/storage") && !this.name.startsWith("/storage/emulated/0/Android/obb") && !this.name.startsWith("/storage/emulated/0/Android/data")) {
14 | Files.set(parseInt(retval), this.name);
15 | send('{"fs":{"function":"open","fd":' + parseInt(retval) + ',"path":"' + this.name + '","flag":"' + this.flag + '"}}');
16 | }
17 | }
18 | });
19 |
20 | Interceptor.attach(Module.findExportByName("libc.so", "remove"), {
21 | onEnter: function (args) {
22 | this.name = args[0].readUtf8String();
23 | },
24 | onLeave(retval) {
25 | if (this.name.startsWith("/storage")) {
26 | send('{"fs":{"function":"remove","status":' + parseInt(retval) + ',"path":"' + this.name + '"}}');
27 | }
28 | }
29 | });
30 |
31 | Interceptor.attach(Module.findExportByName("libc.so", "rename"), {
32 | onEnter: function (args) {
33 | this.src = args[0].readUtf8String();
34 | this.dst = args[1].readUtf8String();
35 | },
36 | onLeave(retval) {
37 | if (((this.src.startsWith("/storage") && !this.src.startsWith("/storage/emulated/0/Android/obb") && !this.src.startsWith("/storage/emulated/0/Android/data")) || (this.dst.startsWith("/storage") && !this.dst.startsWith("/storage/emulated/0/Android/obb") && !this.dst.startsWith("/storage/emulated/0/Android/data"))) && parseInt(retval) == 0) {
38 | send('{"fs":{"function":"rename","source":"' + this.src + '","destination":"' + this.dst + '"}}');
39 | }
40 | }
41 | });
42 |
43 |
44 | Interceptor.attach(Module.findExportByName("libc.so", "read"), {
45 | onEnter: function (args) {
46 | this.fd = parseInt(args[0])
47 | this.addr = args[1]
48 | },
49 | onLeave(retval) {
50 | var len = parseInt(retval);
51 | if (len != 0xFFFFFFFF && len != 0x0 && Files.has(this.fd)) {
52 | send('{"fs":{"function":"read","fd":' + this.fd + ',"path":"' + Files.get(this.fd) + '","data":"' + arrayBufferToBase64(Memory.readByteArray(this.addr, len)) + '"}}');
53 | }
54 | }
55 | });
56 |
57 | Interceptor.attach(Module.findExportByName("libc.so", "close"), {
58 | onEnter: function (args) {
59 | if (Files.has(this.fd)){
60 | send('{"fs":{"function":"close","fd":' + parseInt(retval) + '"}}');
61 | Files.delete(parseInt(args[0]));
62 | }
63 | }
64 | });
65 |
66 | Interceptor.attach(Module.findExportByName("libc.so", "write"), {
67 | onEnter: function (args) {
68 | this.fd = parseInt(args[0])
69 | this.addr = args[1]
70 | },
71 | onLeave(retval) {
72 | var len = parseInt(retval);
73 | if (len != 0xFFFFFFFF && Files.has(this.fd)) {
74 | send('{"fs":{"function":"write","fd":' + this.fd + ',"path":"' + Files.get(this.fd) + '","data":"' + arrayBufferToBase64(Memory.readByteArray(this.addr, len)) + '"}}');
75 | }
76 | }
77 | });
78 |
--------------------------------------------------------------------------------
/amplification.py:
--------------------------------------------------------------------------------
1 | import os
2 | import json
3 | import dpkt
4 | import socket
5 | import pickle
6 | from multiprocessing.pool import ThreadPool
7 |
8 | def amplification_ratio(info):
9 | pkg, addr, port, data = info
10 | res_len = 0
11 | _d = bytes()
12 | try:
13 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
14 | d_len = len(data)
15 | _sent = sock.sendto(data, (addr, port))
16 | sock.settimeout(10)
17 | while True:
18 | r_data, server = sock.recvfrom(10*10000)
19 | _d += r_data
20 | except:
21 | if len(_d)/d_len > 1:
22 | return (pkg, addr, port, data, _d)
23 |
24 | leaks = []
25 | hardcoded_keys = []
26 | all_packets = set()
27 | words_path = []
28 | all_words = []
29 | c = 0
30 | for root, dirnames, filenames in os.walk("./"):
31 | for filename in filenames:
32 | if filename.endswith(".pcap"):
33 | conns_files = []
34 | local_addrs = set()
35 | if os.path.exists(root+"/conn-1.txt"):
36 | conns_file_1 = open(os.path.join(root, "conn-1.txt"), "rb")
37 | conns_files += conns_file_1.readlines()
38 | conns_file_1.close()
39 | if os.path.exists(root+"/conn-2.txt"):
40 | conns_file_2 = open(os.path.join(root, "conn-2.txt"), "rb")
41 | conns_files += conns_file_2.readlines()
42 | conns_file_2.close()
43 |
44 | for conn in conns_files:
45 | if (b"'udp'" in conn or b"'udp6'" in conn) and (not (b":53'," in conn or b":1900'," in conn or b":443'," in conn or b":123'," in conn or b":0'," in conn or b"'null" in conn)) and (b"local_address': '10.42.0" in conn or b"local_address': '/10.42.0" in conn or b"local_address': '::ffff:10.42.0" in conn):
46 | cj = json.loads(
47 | conn.decode().strip().replace("'", '"'))
48 | local_addr = cj["java"]["local_address"] if "java" in cj else cj["native"]["local_address"]
49 | local_addrs.add(local_addr.replace(
50 | "::ffff:", "").replace("/", ""))
51 | if len(local_addrs) == 0:
52 | continue
53 | _pcap = open(root+"/"+filename, "rb")
54 | for _, pkt in dpkt.pcap.Reader(_pcap):
55 | packet = dpkt.ethernet.Ethernet(pkt)
56 | if type(packet.data) == dpkt.ip.IP and type(packet.data.data) == dpkt.udp.UDP and len(packet.data.src) == 4:
57 | if socket.inet_ntoa(packet.data.src)+":"+str(packet.data.data.sport) in local_addrs and int(packet.data.data.dport) not in (53, 0) and not (packet.data.dst[0] == 255 or packet.data.dst[0] in range(224, 240)):
58 | all_packets.add((root, socket.inet_ntoa(packet.data.dst), int(
59 | packet.data.data.dport), packet.data.data.data))
60 |
61 |
62 |
63 |
64 | amplification_rates = dict()
65 | _ar = list()
66 | with ThreadPool(100) as p:
67 | _ar += [data for data in (p.map(amplification_ratio, all_packets)) if data]
68 | with ThreadPool(500) as p:
69 | for (pkg, addr, port, data, rdata) in [data for data in (p.map(amplification_ratio, all_packets)) if data]+_ar:
70 | pkg_name = pkg.split("/")[-1]
71 | rate = len(rdata)/len(data)
72 | if pkg_name in amplification_rates:
73 | if rate > amplification_rates[pkg_name]:
74 | amplification_rates[pkg_name] = rate
75 | else:
76 | amplification_rates[pkg_name] = rate
77 |
78 | with open('amplification_ratio.json', 'w') as outfile:
79 | json.dump(amplification_rates, outfile, indent=4)
80 |
--------------------------------------------------------------------------------
/static.py:
--------------------------------------------------------------------------------
1 | import os
2 | import re
3 | from zipfile import BadZipFile
4 |
5 | from androguard.core.bytecodes.apk import APK
6 | from androguard.core.bytecodes.dvm import DalvikVMFormat
7 |
8 |
9 | class Package:
10 | def __init__(self, package, output="out/"):
11 | self.dexes = set()
12 | for apk_path in [output+package+'/'+f for f in os.listdir(
13 | output+package+'/') if re.match(r'.+\.apk', f)]:
14 | try:
15 | for dex in APK(apk_path).get_all_dex():
16 | try:
17 | self.dexes.add(DalvikVMFormat(dex))
18 | except:
19 | pass
20 | # break
21 | except BadZipFile:
22 | (os.remove(apk_path) for apk_path in [
23 | output+package+'/'+f for f in os.listdir(output+package+'/') if re.match(r'.+\.apk', f)])
24 | os.system('kill -9 {pid}'.format(pid=os.getpid()))
25 |
26 | def get_methods(self, filter):
27 | methods = set()
28 | for dex in self.dexes:
29 | for method in dex.get_methods():
30 | if method.get_name().endswith(b"-impl"):
31 | continue
32 | new_method = Method()
33 | new_method.into(method)
34 | if method.get_name().decode("utf-8").find(' ') == -1 and method.get_name().decode("utf-8").find('-') == -1 and method.class_name.decode("utf-8").find('$') == -1 and method.get_descriptor().decode("utf-8").find('$') == -1 and not method.class_name.decode("utf-8").endswith("Impl;") and not (method.get_access_flags() & 0x100) == 0x100:
35 | if filter(new_method):
36 | print(method.class_name)
37 | print(method.get_name())
38 | methods.add(new_method)
39 | return methods
40 |
41 |
42 | class Method:
43 | def into(self, method):
44 | self.class_name = (method.get_class_name(
45 | )[1:].decode("utf-8").rstrip(';').replace('/', '.'))
46 | self.name = ("$init" if method.get_name().decode("utf-8") ==
47 | "" else method.get_name().decode("utf-8"))
48 | self.params, self.return_type = description_mapper(
49 | method.get_descriptor())
50 |
51 | def to_jni(self):
52 | return "Java_"+jni_translation(self.class_name).replace('.', "_")+"_"+jni_translation(self.name)
53 |
54 | def to_frida(self, body=lambda method, body: "", ret=""):
55 | params = {}
56 | for i, param in enumerate(self.params):
57 | params["p"+str(i)] = param
58 | if ret == "":
59 | ret = "return this."+self.name + \
60 | "("+(", ".join([key for key, value in params.items()]))+")"
61 | return "try{Java.use('"+self.class_name+"')."+self.name+".overload("+("" if len(params) == 0 else "'"+"', '".join([value for key, value in params.items()])+"'")+").implementation = function ("+", ".join([key for key, value in params.items()])+") {"+body(self, params)+";"+ret+"};} catch(_e) {}"
62 |
63 |
64 | def jni_translation(_str):
65 | return _str.replace('_', '_1').replace(';', '_2').replace('[', '_3')
66 |
67 |
68 | def description_mapper(description):
69 | types = {
70 | "V": "void",
71 | "Z": "boolean",
72 | "B": "byte",
73 | "S": "short",
74 | "C": "char",
75 | "I": "int",
76 | "J": "long",
77 | "F": "float",
78 | "D": "double",
79 | }
80 | description, return_type = description.split(")", 1)
81 | param_list = list()
82 | return_type = types[return_type] if return_type in types else "[" + \
83 | types[return_type[1:]] if return_type[1:] in types else return_type.replace(
84 | "/", ".")
85 | ret = return_type if type(return_type) == str else return_type.decode()
86 |
87 | for params in description[1:].split(" "):
88 | if params in types and params[0] != "[":
89 | param_list.append((types[params] if type(
90 | types[params]) == str else types[params].decode()))
91 | elif len(params) != 0:
92 | if len(params) != 0 and params[0] == "[":
93 | param_list.append("["+(params[1:] if type(params[1:])
94 | == str else params[1:].decode()).replace("/", "."))
95 | else:
96 | param_list.append((params[1:len(params)-1] if type(params[1:len(
97 | params)-1]) == str else params[1:len(params)-1].decode()).replace("/", "."))
98 |
99 | return param_list, ret
100 |
101 | # def description_mapper(description):
102 | # types = {
103 | # "V": "void",
104 | # "Z": "boolean",
105 | # "B": "byte",
106 | # "S": "short",
107 | # "C": "char",
108 | # "I": "int",
109 | # "J": "long",
110 | # "F": "float",
111 | # "D": "double",
112 | # }
113 | # description, return_type = description.split(")", 1)
114 | # param_list = list()
115 | # return_type = types[return_type] if return_type in types else "[" + \
116 | # types[return_type[1:]] if return_type[1:] in types else return_type.replace(
117 | # "/", ".")
118 |
119 | # for params in description[1:].split(" "):
120 | # if params in types and params[0] != "[":
121 | # param_list.append(bytes(types[params], encoding='utf8'))
122 | # elif len(params) != 0:
123 | # if len(params) != 0 and params[0] == "[":
124 | # param_list.append(b"["+params[1:].replace("/", "."))
125 | # else:
126 | # param_list.append(params[1:len(params)-1].replace("/", "."))
127 |
128 | # return param_list, return_type
129 |
--------------------------------------------------------------------------------
/js/media.js:
--------------------------------------------------------------------------------
1 | setTimeout(function() {
2 | Java.perform(function() {
3 | var MediaMuxer = Java.use("android.media.MediaMuxer");
4 | var AudioRecord = Java.use("android.media.AudioRecord");
5 | var MediaProjection = Java.use("android.media.projection.MediaProjection");
6 | var MediaProjectionManager = Java.use("android.media.projection.MediaProjectionManager");
7 | var Camera = Java.use("android.hardware.Camera");
8 | var CameraDevice = Java.use("android.hardware.camera2.CameraDevice");
9 |
10 |
11 | Camera.open.overload('int').implementation = function(p0) {
12 | var ret = this.open(p0);
13 | send('{"media":"{\\"class_name\\":\\"android.hardware.Camera\\",\\"method_name\\":\\"open\\",\\"args\\":[' + p0 + '],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
14 | return ret;
15 | }
16 |
17 | Camera.open.overload().implementation = function() {
18 | var ret = this.open();
19 | send('{"media":"{\\"class_name\\":\\"android.hardware.Camera\\",\\"method_name\\":\\"open\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
20 | return ret;
21 | }
22 | Camera.release.overload().implementation = function() {
23 | var ret = this.release();
24 | send('{"media":"{\\"class_name\\":\\"android.hardware.Camera\\",\\"method_name\\":\\"release\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
25 | return ret;
26 | }
27 |
28 | CameraDevice.createCaptureRequest.overload('int').implementation = function(p0) {
29 | var ret = this.createCaptureRequest(p0);
30 | send('{"media":"{\\"class_name\\":\\"android.hardware.camera2.CameraDevice\\",\\"method_name\\":\\"createCaptureRequest\\",\\"args\\":[' + p0 + '],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
31 | return ret;
32 | }
33 |
34 | CameraDevice.close.overload().implementation = function() {
35 | var ret = this.close();
36 | send('{"media":"{\\"class_name\\":\\"android.hardware.camera2.CameraDevice\\",\\"method_name\\":\\"close\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
37 | return ret;
38 | }
39 |
40 | CameraDevice.createCaptureRequest.overload('int').implementation = function(p0) {
41 | var ret = this.createCaptureRequest(p0);
42 | send('{"media":"{\\"class_name\\":\\"android.hardware.camera2.CameraDevice\\",\\"method_name\\":\\"createCaptureRequest\\",\\"args\\":[' + p0 + '],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
43 | return ret;
44 | }
45 |
46 | MediaMuxer.start.implementation = function() {
47 | var ret = this.start();
48 | send('{"media":"{\\"class_name\\":\\"android.media.MediaMuxer\\",\\"method_name\\":\\"start\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
49 | return ret;
50 | }
51 |
52 | MediaMuxer.stop.implementation = function() {
53 | var ret = this.stop();
54 | send('{"media":"{\\"class_name\\":\\"android.media.MediaMuxer\\",\\"method_name\\":\\"stop\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
55 | return ret;
56 | }
57 |
58 | MediaProjection.stop.implementation = function() {
59 | var ret = this.stop();
60 | send('{"media":"{\\"class_name\\":\\"android.media.projection.MediaProjection\\",\\"method_name\\":\\"stop\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
61 | return ret;
62 | }
63 |
64 | MediaProjectionManager.createScreenCaptureIntent.implementation = function() {
65 | var ret = this.createScreenCaptureIntent();
66 | send('{"media":"{\\"class_name\\":\\"android.media.projection.MediaProjectionManager\\",\\"method_name\\":\\"createScreenCaptureIntent\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
67 | return ret;
68 | }
69 | AudioRecord.startRecording.overload().implementation = function() {
70 | var ret = this.startRecording();
71 | send('{"media":"{\\"class_name\\":\\"android.media.AudioRecord\\",\\"method_name\\":\\"startRecording\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
72 | return ret;
73 | }
74 | AudioRecord.stop.overload().implementation = function() {
75 | var ret = this.stop();
76 | send('{"media":"{\\"class_name\\":\\"android.media.AudioRecord\\",\\"method_name\\":\\"stop\\",\\"args\\":[],\\"ret\\":\\"\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
77 | return ret;
78 | }
79 | });
80 | }, 0);
--------------------------------------------------------------------------------
/js/bypass_root_detection.js:
--------------------------------------------------------------------------------
1 | setTimeout(function () {
2 | Java.perform(function () {
3 | var RootPackages = ["com.topjohnwu.magisk"];
4 | var RootBins = ["su", "busybox"];
5 |
6 | Java.use("android.app.ApplicationPackageManager").getPackageInfoAsUser.implementation = function (packageName, flags, userId) {
7 | if (RootPackages.indexOf(packageName) > -1) {
8 | packageName = "fake.fake.fake.fake.fake.package";
9 | }
10 | return this.getPackageInfoAsUser(packageName, flags, userId);
11 | } //Android 11
12 | Java.use("android.app.ApplicationPackageManager").getPackageInfo.overload('java.lang.String', 'int').implementation = function (packageName, flags) {
13 | if (RootPackages.indexOf(packageName) > -1) {
14 | packageName = "fake.fake.fake.fake.fake.package";
15 | }
16 | return this.getPackageInfo(packageName, flags);
17 | }
18 | // Java.use('android.content.pm.PackageManager').getPackageInfo.overload('java.lang.String', 'int').implementation = function (packageName, flags) {
19 | // console.log("-------------------------")
20 | // console.log(packageName);
21 | // if (RootPackages.indexOf(packageName) > -1) {
22 | // packageName = "fake.fake.fake.fake.fake.package";
23 | // }
24 | // return this.getPackageInfo(packageName, flags);
25 | // }
26 | Java.use('java.lang.Runtime').exec.overload('[Ljava.lang.String;').implementation = function (cmd) {
27 | console.log(cmd)
28 | if (cmd[0] == "which" ||cmd[0] == "su" || cmd[0] == "mount" || RootBins.indexOf(cmd[0]) || RootBins.indexOf(cmd[1])) {
29 | return this.exec([]);
30 | }
31 | return this.exec(cmd);
32 | }
33 | Java.use('java.lang.String').contains.overload('java.lang.CharSequence').implementation = function (charSequence) {
34 | if (charSequence.toString() == "test-keys") {
35 | return false;
36 | }
37 | return this.contains(charSequence);
38 | }
39 | Java.use('java.lang.Runtime').exec.overload('java.lang.String').implementation = function (command) {
40 | // console.log(command)
41 |
42 | if (command.match(/.*which\s.*su/) || command.match(/mount/)) {
43 | console.log(command)
44 | return this.exec(Java.use("java.lang.String").$new("which D4my").toString());
45 | }
46 |
47 | if (command.match(/su/)) {
48 | return this.exec(Java.use("java.lang.String").$new("D4my").toString());
49 | }
50 | // if (command.match(/getprop/)) {
51 | // return this.exec(command + " | grep -v ro.debuggable");
52 | // }
53 | return this.exec(command);
54 | }
55 | Java.use('java.io.File').$init.overload('java.lang.String', 'java.lang.String').implementation = function (path, file) {
56 | if (["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk", "magisk"].includes(file)) {
57 | return this.$init(path, Java.use("java.lang.String").$new("D4my").toString());
58 | } else {
59 | return this.$init(path, file);
60 | };
61 | }
62 | Java.use('java.io.File').$init.overload('java.io.File', 'java.lang.String').implementation = function (path, file) {
63 | if (["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk", "magisk"].includes(file)) {
64 | return this.$init(path, Java.use("java.lang.String").$new("D4my").toString());
65 | } else {
66 | return this.$init(path, file);
67 | };
68 | }
69 | Java.use('java.io.File').$init.overload('java.lang.String').implementation = function (file) {
70 | if (["/data/local/su",
71 | "/data/local/bin/su",
72 | "/data/local/xbin/su",
73 | "/sbin/su",
74 | "/su/bin/su",
75 | "/system/bin/su",
76 | "/system/bin/.ext/su",
77 | "/system/bin/failsafe/su",
78 | "/system/sd/xbin/su",
79 | "/system/usr/we-need-root/su",
80 | "/system/xbin/su/su",
81 | "/system/app/Superuser.apk",
82 | "/cache/su",
83 | "/system/xbin/busybox",
84 | "/system/bin/magisk",
85 | "/data/su",
86 | "/dev/su"
87 | ].includes(file)) {
88 | return this.$init(Java.use("java.lang.String").$new("D4my").toString());;
89 | } else {
90 | return this.$init(file)
91 | };
92 | }
93 | try {
94 | Java.use('android.location.Location').isMock.implementation = function () {
95 | return false;
96 | }
97 | Java.use('android.location.Location').isFromMockProvider.implementation = function () {
98 | return false;
99 | }
100 | } catch (_) { }
101 | });
102 |
103 | Interceptor.attach(Module.findExportByName("libc.so", "fopen"), {
104 | onEnter: function (args) {
105 | this.path = Memory.readCString(args[0]).split("/");
106 | },
107 | onLeave: function (retval) {
108 | var path = this.path;
109 | if ((["su", "busybox", "supersu", "Superuser.apk", "KingoUser.apk", "SuperSu.apk", "magisk"].indexOf(path[path.length - 1]) > -1)) {
110 | retval.replace(0x0);
111 | }
112 | }
113 | });
114 |
115 | Interceptor.attach(Module.findExportByName("libc.so", "system"), {
116 | onEnter: function (args) {
117 | this.cmd = Memory.readCString(args[0]);
118 | },
119 | onLeave: function (retval) {
120 | var cmd = this.cmd;
121 | if (cmd == "su" || cmd.indexOf("getprop") != -1 || cmd == "mount" || cmd.indexOf("build.prop") != -1) {
122 | retval.replace(0x0);
123 | }
124 | }
125 | });
126 | }, 1);
--------------------------------------------------------------------------------
/helper/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import device
2 | import functools
3 | import sys
4 | import exceptions
5 | import hooker
6 | import time
7 | import static
8 | import dynamic
9 | import logging
10 | import os
11 | import shutil
12 |
13 | # logging.debug(list(substring in "aaass" for substring in ['java/security', 'javax/crypto/spec']))
14 |
15 | root = logging.getLogger()
16 | root.setLevel(logging.DEBUG)
17 |
18 | ch = logging.StreamHandler(sys.stdout)
19 | ch.setLevel(logging.DEBUG)
20 | FORMAT = "[%(asctime)s - %(filename)s:%(lineno)s - %(funcName)s() ] %(message)s"
21 | formatter = logging.Formatter(FORMAT)
22 | ch.setFormatter(formatter)
23 | root.addHandler(ch)
24 |
25 |
26 | def main():
27 | logging.debug("value")
28 | try:
29 | devices = device.get_active_devices()
30 | except:
31 | _, value, _ = sys.exc_info()
32 | logging.debug(value)
33 | sys.exit(1)
34 | else:
35 | cdevice = None
36 | # print(devices)
37 | for d in devices:
38 | if d.d.serialno == "10.42.0.27:5555":
39 | # continue
40 | cdevice = d
41 | break
42 | cdevice = d
43 | print(cdevice.d.serialno)
44 | cdevice.close_all_apps()
45 | # cdevice = devices[0]
46 |
47 | with open("packages.txt", "r") as packages:
48 | for _i, pkg_name in enumerate(packages.read().splitlines()):
49 | # if i < 20:
50 | # continue
51 | # pkg_name = "com.trtf.blue"
52 |
53 | if (not os.path.exists("out/" + pkg_name+"/"+pkg_name + ".pcap") or not os.path.exists("out/" + pkg_name + "/mitmdump")):
54 | if os.path.exists("out/" + pkg_name+"/"):
55 | for f in os.listdir("out/" + pkg_name+"/"):
56 | if f.endswith('.png') or f.endswith('.txt') or f.endswith('.lock'):
57 | os.remove("out/" + pkg_name+"/"+f)
58 | if os.path.exists("out/" + pkg_name + "/mitmdump"):
59 | os.remove("out/" + pkg_name + "/mitmdump")
60 | if os.path.exists("out/" + pkg_name + "/files-1"):
61 | shutil.rmtree("out/" + pkg_name + "/files-1")
62 | if os.path.exists("out/" + pkg_name + "/files-2"):
63 | shutil.rmtree("out/" + pkg_name + "/files-2")
64 | if os.path.exists("out/" + pkg_name+"/"+pkg_name + ".pcap"):
65 | os.remove("out/" + pkg_name+"/"+pkg_name + ".pcap")
66 | elif os.path.exists("out/" + pkg_name+".fail"):
67 | continue
68 | else:
69 | continue
70 | cdevice.uninstall_3rd_party_apps()
71 | #pkg_name = "com.apple.movetoios"
72 | logging.debug(pkg_name)
73 | if cdevice.install_app(pkg_name, reinstall=False) == False:
74 | continue
75 | cdevice.store_app(pkg_name)
76 | # static_analysis = None
77 | static_analysis = static.Package(pkg_name)
78 | perms, service_name = cdevice.grant_app_permissions(pkg_name)
79 | (p, mitm) = cdevice.start_capture(pkg_name)
80 | h = dynamic.Dynamic(cdevice, pkg_name, static_analysis)
81 | h.run()
82 | analysis_time = int(time.time())
83 | with open("out/"+pkg_name+"/time.txt", "a") as f:
84 | f.write("s1+:"+str(analysis_time)+"\n")
85 | cdevice.run_app(pkg_name)
86 | cdevice.start_interaction(pkg_name, 1, analysis_time)
87 | cdevice.close_app(pkg_name)
88 | with open("out/"+pkg_name+"/time.txt", "a") as f:
89 | f.write("s1-:"+str(int(time.time()))+"\n")
90 | cdevice.store_files(pkg_name, 1)
91 | if os.path.exists("out/"+pkg_name+"/crypt-1.txt") and 1==2:
92 | logging.debug("======> "+pkg_name+" 2nd")
93 | open("out/"+pkg_name+"/2nd.lock", 'a').close()
94 | if cdevice.install_app(pkg_name, reinstall=True) == False:
95 | raise "Unable to install"
96 | cdevice.grant_app_permissions(
97 | pkg_name, perms=perms, service_name=service_name)
98 | analysis_time = int(time.time())
99 | with open("out/"+pkg_name+"/time.txt", "a") as f:
100 | f.write("s2+:"+str(analysis_time)+"\n")
101 | cdevice.run_app(pkg_name)
102 | cdevice.start_interaction(pkg_name, 2, analysis_time)
103 | cdevice.close_app(pkg_name)
104 | with open("out/"+pkg_name+"/time.txt", "a") as f:
105 | f.write("s2-:"+str(int(time.time()))+"\n")
106 | cdevice.store_files(pkg_name, 2)
107 | os.remove("out/"+pkg_name+"/2nd.lock")
108 | h.stop()
109 | cdevice.stop_capture(p, mitm, pkg_name)
110 | cdevice.uninstall_app(pkg_name)
111 | # break
112 | # package = static.Package(pkg_name)
113 | # # native_methods = package.get_methods(lambda m: (
114 | # # m.get_access_flags() & 0x100) == 0x100) # 0x100 means native
115 | # # native_methods = package.get_methods(
116 | # # lambda m: (m.get_name() in ("encrypt", "decrypt") or any(substring in m.get_descriptor().decode("utf-8") for substring in ['java/security', 'javax/crypto/spec'])))
117 | # native_methods = package.get_methods(
118 | # lambda m: (m.get_name() in ("encrypt", "decrypt") or m.get_name().decode("utf-8").startswith("hash")))
119 | # jscode = "Java.perform(function () {"+("".join((m.to_frida(p).decode("utf-8")
120 | # for m in native_methods)))+"});"
121 | # logging.debug(jscode)
122 | # with open("js/bypass_root_detection.js") as f:
123 | # jscode += f.read()
124 | # # logging.debug(cdevice.is_alive())
125 | # cdevice.frida.on("spawn-added", functools.partial(hooker.spawn_added,
126 | # package=pkg_name, jscode=jscode, frida_device=cdevice.frida, processes=dict()))
127 | # cdevice.frida.enable_spawn_gating()
128 | # logging.debug("x")
129 | # sys.stdin.read()
130 |
131 |
132 | if __name__ == '__main__':
133 | main()
134 |
135 | # for i in `find . -name "*.pcap" -type f`; do
136 | # python ../pcap-full.py "$i"
137 | # done
138 |
--------------------------------------------------------------------------------
/helper/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/js/general.js:
--------------------------------------------------------------------------------
1 | var JavaConnectionPool = {};
2 | var Modules = {};
3 | const Files = new Map();
4 |
5 |
6 | function base64(input) {
7 | var _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
8 | var output = "";
9 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
10 | var i = 0;
11 | while (i < input.length) {
12 | chr1 = input.charCodeAt(i++);
13 | chr2 = input.charCodeAt(i++);
14 | chr3 = input.charCodeAt(i++);
15 | enc1 = chr1 >> 2;
16 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
17 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
18 | enc4 = chr3 & 63;
19 | if (isNaN(chr2)) {
20 | enc3 = enc4 = 64;
21 | } else if (isNaN(chr3)) {
22 | enc4 = 64;
23 | }
24 |
25 | output = output + _keyStr.charAt(enc1) + _keyStr.charAt(enc2) + _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
26 | }
27 | return output;
28 | }
29 |
30 |
31 | function btoa(p) {
32 | if (p == null) {
33 | return ''
34 | } else {
35 | if (typeof (p) === 'string') {
36 | var p = Java.use('java.lang.String').$new(p).getBytes();
37 | }
38 | try {
39 | if (p.$className == "java.nio.HeapByteBuffer") {
40 | p = p.array();
41 | }
42 | var Base64 = Java.use('android.util.Base64');
43 | var base64encode = Base64.encodeToString.overload('[B', 'int');
44 | return base64encode.call(Base64, p, 2);
45 | } catch (_e) {
46 | return arrayBufferToBase64(p);
47 | }
48 | }
49 | }
50 |
51 | function arrayBufferToBase64(buffer) {
52 | var binary = '';
53 | var bytes = new Uint8Array(buffer);
54 | var len = bytes.byteLength;
55 | for (var i = 0; i < len; i++) {
56 | binary += String.fromCharCode(bytes[i]);
57 | }
58 |
59 | return base64(binary);
60 |
61 | }
62 | function ntohs(val) {
63 | return ((val & 0xFF) << 8) | ((val >> 8) & 0xFF);
64 | }
65 |
66 | function inet_pton(a) {
67 | let m
68 | let i
69 | let j
70 | const f = String.fromCharCode
71 |
72 | m = a.match(/^(?:\d{1,3}(?:\.|$)){4}/)
73 | if (m) {
74 | m = m[0].split('.')
75 | m = f(m[0], m[1], m[2], m[3])
76 | // Return if 4 bytes, otherwise false.
77 | if (m.length === 4) {
78 | var ret = new Uint8Array(4);
79 | for (var ii = 0; ii < m.length; ii++) {
80 | ret[ii] = m.charCodeAt(ii);
81 | }
82 | return ret;
83 | } else {
84 | return false;
85 | }
86 | // return m.length === 4 ? new Uint8Array(m.split("")
87 | // .map(c => c.charCodeAt(0).toString(16).padStart(2, "0"))) : false
88 | }
89 |
90 | // IPv6
91 | if (a.length > 39) {
92 | return false
93 | }
94 |
95 | m = a.split('::')
96 |
97 | if (m.length > 2) {
98 | return false
99 | } // :: can't be used more than once in IPv6.
100 |
101 | const reHexDigits = /^[\da-f]{1,4}$/i
102 |
103 | for (j = 0; j < m.length; j++) {
104 | if (m[j].length === 0) { // Skip if empty.
105 | continue
106 | }
107 | m[j] = m[j].split(':')
108 | for (i = 0; i < m[j].length; i++) {
109 | let hextet = m[j][i]
110 | if (!reHexDigits.test(hextet)) {
111 | return false
112 | }
113 |
114 | hextet = parseInt(hextet, 16)
115 | if (isNaN(hextet)) {
116 | return false
117 | }
118 | m[j][i] = f(hextet >> 8, hextet & 0xFF)
119 | }
120 | m[j] = m[j].join('')
121 | }
122 | var final = m.join('\x00'.repeat(16 - m.reduce((tl, m) => tl + m.length, 0)));
123 |
124 | var ret = new Uint8Array(16);
125 | for (var ii = 0; ii < final.length; ii++) {
126 | ret[ii] = final.charCodeAt(ii);
127 | }
128 | return ret;
129 |
130 | }
131 | function arrayBuffer(buffer) {
132 | var binary = '';
133 | var bytes = new Uint8Array(buffer);
134 | var len = bytes.byteLength;
135 | for (var i = 0; i < len; i++) {
136 | binary += String.fromCharCode(bytes[i]);
137 | }
138 | return (binary);
139 |
140 | }
141 | function inet_ntop(v) { //https://github.com/locutusjs/locutus/blob/master/src/php/network/inet_ntop.js
142 | var a = arrayBuffer(v);
143 | let i = 0
144 | let m = ''
145 | const c = []
146 | a += ''
147 | if (a.length === 4) {
148 | return [a.charCodeAt(0), a.charCodeAt(1), a.charCodeAt(2), a.charCodeAt(3)].join('.')
149 | } else if (a.length === 16) {
150 | for (i = 0; i < 16; i++) {
151 | c.push(((a.charCodeAt(i++) << 8) + a.charCodeAt(i)).toString(16))
152 | }
153 | return c.join(':').replace(/((^|:)0(?=:|$))+:?/g, function (t) {
154 | m = (t.length > m.length) ? t : m
155 | return t
156 | }).replace(m || ' ', '::')
157 | } else {
158 | return null
159 | }
160 | }
161 | function ipv4t6(a) {
162 | var z = inet_pton(a)
163 | if (z == false) {
164 | return false
165 | }
166 | var ar = new Uint8Array(16);
167 | for (var i = 0; i < 4; i++) {
168 | ar[12 + i] = z[i];
169 | }
170 | return inet_ntop(ar);
171 | }
172 |
173 | var proxy_addr4 = "10.42.0.1"
174 | var proxy_addr6 = ipv4t6(proxy_addr4)
175 |
176 | Java.perform(function () {
177 | try {
178 | Java.use('java.lang.System').exit.implementation = function (v) {
179 | // console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
180 | return this.exit(v);
181 | }
182 | } catch (_) { }
183 | try {
184 | Java.use('android.app.KeyguardManager').isDeviceSecure.overload().implementation = function (v) {
185 |
186 | // console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
187 | return true;
188 | }
189 | } catch (_) { }
190 | try {
191 | Java.use("android.app.ApplicationPackageManager").getInstallerPackageName.implementation = function (_packageName) {
192 | // console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
193 | return Java.use("java.lang.String").$new("com.android.vending").toString();;
194 | }
195 | } catch (_) { }
196 | try {
197 | Java.use('android.content.pm.InstallSourceInfo').getInstallingPackageName.implementation = function () {
198 | return Java.use("java.lang.String").$new("com.android.vending").toString();
199 | }
200 | } catch (_) { }
201 |
202 | });
203 |
204 | // Process.enumerateModules()
205 | // .forEach(function (m) {
206 | // if (m.path.startsWith("/apex/") || m.path.startsWith("/data/app/")) {
207 | // Memory.protect(m.base, m.size, 'rwx');
208 | // }
209 | // });
210 |
211 |
--------------------------------------------------------------------------------
/js/native.js:
--------------------------------------------------------------------------------
1 |
2 | // function inet4_ntoa(int) {
3 | // return ((int >> 24) & 255) + "." + ((int >> 16) & 255) + "." + ((int >> 8) & 255) + "." + (int & 255);
4 | // }
5 |
6 | // Interceptor.attach(Module.findExportByName("libc.so", "pthread_create"), {
7 | // onEnter: function (args) {
8 | // this.id = null
9 | // this.m = null;
10 | // // console.log('Pthreaaaaad from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
11 | // // console.log(JSON.stringify(this.context));
12 | // // console.log("Pthreaaaaad from"+DebugSymbol.fromAddress(this.context.lr).moduleName)
13 | // if (Process.enumerateModules()
14 | // .filter(function (m) {
15 | // // return true;
16 | // return m.path.startsWith("/data/app/") && m.path.endsWith(".so");
17 | // }).map(function (m) {
18 | // return m.name;
19 | // }).includes(DebugSymbol.fromAddress(this.context.lr).moduleName)) {
20 | // this.id = args[0]
21 | // this.m = DebugSymbol.fromAddress(this.context.lr).moduleName
22 |
23 | // console.log(DebugSymbol.fromAddress(this.context.lr));
24 | // console.log("----");
25 | // console.log(DebugSymbol.fromAddress(args[2]));
26 | // console.log("----");
27 |
28 | // console.log(JSON.stringify(this.context, null, 2));
29 |
30 | // console.log('pthread_create called from:\n' +
31 | // Thread.backtrace(this.context, Backtracer.ACCURATE) // FUZZY ACCURATE
32 | // .map(DebugSymbol.fromAddress).join('\n') + '\n');
33 |
34 |
35 | // }
36 |
37 | // },
38 | // onLeave: function (retval) {
39 | // if (this.id) {
40 | // console.log(this.m + "===>" + ptr(this.id).readUInt())
41 | // }
42 | // // if (this.flag) // passed from onEnter
43 | // // console.warn("\nretval: " + retval);
44 | // }
45 | // });
46 |
47 |
48 | Process
49 | .getModuleByName({ linux: 'libc.so', darwin: 'libSystem.B.dylib', windows: 'ws2_32.dll' }[Process.platform])
50 | .enumerateExports().filter(ex => ex.type === 'function' && ['connect', 'recv', 'send', 'sendto', 'recvfrom', 'accept', 'listen', 'bind'].some(prefix => ex.name.indexOf(prefix) === 0))
51 | .forEach(ex => {
52 | Interceptor.attach(ex.address, {
53 | onEnter: function (args) {
54 | this.fd = args[0].toInt32();
55 | this.socketType = Socket.type(this.fd);
56 | if (this.socketType == 'tcp' || this.socketType == 'udp' || this.socketType == 'tcp6' || this.socketType == 'udp6') {
57 | this.ipAddress = null;
58 | this.portAddress = null;
59 | this.localIpAddress = null;
60 | this.localPortAddress = null;
61 |
62 |
63 | var address = Socket.peerAddress(this.fd);
64 | var local_address = Socket.localAddress(this.fd);
65 | if (address != null) {
66 | this.ipAddress = address.ip;
67 | this.portAddress = address.port;
68 | }
69 | if (local_address != null) {
70 | this.localIpAddress = local_address.ip;
71 | this.localPortAddress = local_address.port;
72 | }
73 | if (ex.name == "connect" || ex.name == "bind" || ex.name == "accept") {
74 | this.portAddress = ntohs(Memory.readU16(ptr(args[1]).add(2)));
75 | this.ipAddress = inet_ntop(Memory.readByteArray(ptr(args[1]).add(this.socketType.slice(-1) == '6' ? 8 : 4), this.socketType.slice(-1) == '6' ? 16 : 4));
76 | if (ex.name == "connect" && this.portAddress == 443 && this.socketType.startsWith('tcp')) {
77 | var socketType = this.socketType;
78 | Process.enumerateRanges('rw-')
79 | .forEach(function (m) {
80 | if (m.base.toInt32() < args[1].toInt32() && args[1].toInt32() - m.base.toInt32() < m.size) {
81 | // console.log(this.portAddress)
82 | ptr(args[1]).add(2).writeU16(36895);
83 | if (socketType.slice(-1) == '6') {
84 | ptr(args[1]).add(8).writeByteArray(inet_pton(proxy_addr6));
85 | } else {
86 | ptr(args[1]).add(4).writeByteArray(inet_pton(proxy_addr4));
87 | }
88 | }
89 | });
90 | //00 00 00 00 00 00 00 00 00 00 ff ff 0a 2a 00 01
91 | //36895
92 | //::ffff:a2a:1
93 | //0a 2a 00 01
94 | //10.42.0.1
95 | }
96 | if (ex.name == "bind") {
97 | this.localPortAddress = this.portAddress;
98 | this.localIpAddress = this.ipAddress;
99 | }
100 | } else if ((ex.name == "sendto" || ex.name == "recvfrom") && args[4] != 0x0) {
101 | this.portAddress = ntohs(Memory.readU16(ptr(args[4]).add(2)));
102 | this.ipAddress = inet_ntop(Memory.readByteArray(ptr(args[4]).add(this.socketType.slice(-1) == '6' ? 8 : 4), this.socketType.slice(-1) == '6' ? 16 : 4));
103 | }
104 | if (ex.name == "listen" || ex.name == "bind") {
105 | this.portAddress = null;
106 | this.ipAddress = null;
107 | }
108 | // if (this.portAddress == null || this.ipAddress == null || this.localPortAddress == null || this.localIpAddress == null) {
109 | // console.log(ex.name);
110 | // return
111 | // }
112 | }
113 |
114 | },
115 | onLeave: function (retval) {
116 | if (this.socketType == 'tcp' || this.socketType == 'udp' || this.socketType == 'tcp6' || this.socketType == 'udp6') {
117 | if (this.localPortAddress == 0 && ex.name == "connect") {
118 | var local_address = Socket.localAddress(this.fd);
119 | if (local_address != null) {
120 | this.localIpAddress = local_address.ip;
121 | this.localPortAddress = local_address.port;
122 | }
123 | }
124 | if (JavaConnectionPool[(this.ipAddress + ':' + this.portAddress).replace(/^::ffff:/, '')] !== undefined && JavaConnectionPool[(this.ipAddress + ':' + this.portAddress).replace(/^::ffff:/, '')].includes((this.localIpAddress + ':' + this.localPortAddress).replace(/^::ffff:/, ''))) {
125 | send('{"java":{"protocol":"' + this.socketType + '","fd":"' + this.fd + '","function":"' + ex.name + '","pid":' + Process.id + ',"address":"' + this.ipAddress + ':' + this.portAddress + '","local_address":"' + this.localIpAddress + ':' + this.localPortAddress + '"}}');
126 |
127 | } else {
128 | send('{"native":{"protocol":"' + this.socketType + '","fd":"' + this.fd + '","function":"' + ex.name + '","pid":' + Process.id + ',"address":"' + this.ipAddress + ':' + this.portAddress + '","local_address":"' + this.localIpAddress + ':' + this.localPortAddress + '"}}');
129 | }
130 | if (ex.name == "connect" && (this.ipAddress == "127.0.0.1" || this.ipAddress == "::ffff:7f00:1" || this.ipAddress == "::1") && this.portAddress == 27042 && this.socketType.startsWith('tcp')) {
131 | retval.replace(-1);
132 | }
133 | }
134 | }
135 |
136 | })
137 | })
138 |
139 |
--------------------------------------------------------------------------------
/dynamic.py:
--------------------------------------------------------------------------------
1 | import time
2 | import json
3 | import functools
4 | import logging
5 | import os
6 | import sys
7 | import subprocess
8 |
9 |
10 | def fh(method, body):
11 | params = ""
12 | for i, (key, _) in enumerate(body.items()):
13 | if i > 0:
14 | params += "+'\\\\\", \\\\\"'+"
15 | # params += "+'\\\\\"], [\\\\\"'+"
16 | params += "btoa(" + key+")"
17 | #Java.use('android.provider.Settings$Secure').getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id')
18 | exec = "var ret = this." + \
19 | method.name+"("+(", ".join([key for key, value in body.items()]))+");"
20 | return exec+"send('{\"crypto\":\"{\\\\\"class_name\\\\\":\\\\\""+method.class_name+"\\\\\",\\\\\"method_name\\\\\":\\\\\""+method.name+"\\\\\",\\\\\"args\\\\\":["+("\\\\\"'+"+params+"+'\\\\\"" if params else "")+"],\\\\\"ret\\\\\":\\\\\"'+btoa(ret)+'\\\\\",\\\\\"stackTrace\\\\\":\\\\\"'+btoa(Java.use(\"android.util.Log\").getStackTraceString(Java.use(\"java.lang.Exception\").$new()))+'\\\\\"}\"}');return ret;"
21 | #console.log('"+method.class_name.decode("utf-8")+":"+method.name.decode("utf-8")+"("+("'+"+params+"+'" if params else "")+")->'+ret);
22 |
23 | #Java.use('android.provider.Settings$Secure').getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id');
24 |
25 |
26 | class Dynamic:
27 | def __init__(self, device, package, static):
28 | self.frida = device.frida
29 | self.device = device
30 | self.package = package
31 | self.sessions = set()
32 | self.jscode = str()
33 |
34 | def candid_methods(
35 | m): return "java.lang.String" in m or "java.lang.Byte" in m or "byte" == m
36 | # args , ret = description_mapper(method.get_descriptor())
37 | # self.params, self.return_type
38 | rooted_methods = static.get_methods(
39 | lambda m: (("rooted" in m.name.lower()) and "path" not in m.class_name and ".db." not in m.class_name and "google" not in m.class_name and "kotlin" not in m.class_name and m.return_type == "boolean"))
40 | self.jscode = "Java.perform(function () {"+(
41 | "".join((m.to_frida((lambda _m, _b: ""), "return false;") for m in rooted_methods)))+(
42 | "".join((m.to_frida((lambda _m, _b: "p0 = false;")) for m in static.get_methods(
43 | lambda m: (("root" in m.name.lower() and "detect" in m.name.lower()) and ".db." not in m.class_name and "path" not in m.class_name and "google" not in m.class_name and m.return_type == "void" and len(m.params) == 1 and m.params[0] == "boolean")))))+"});"
44 |
45 | # fake_verifiers = static.get_methods(
46 | # lambda m: (("verify" == m.name.lower()) and "google" not in m.class_name and "java" not in m.class_name and "kotlin" not in m.class_name and m.return_type == "boolean" and len(m.params) == 2))
47 |
48 | # self.jscode = "Java.perform(function () {"+(
49 | # "".join((m.to_frida((lambda _m, _b: ""), "return true;") for m in fake_verifiers)))+"});"
50 |
51 | # self.jscode += "Java.perform(function () {"+(
52 | # "".join((m.to_frida((lambda _m,_b: "p0 = false;")) for m in static.get_methods(
53 | # lambda m: (("root" in m.name.lower() and "detect" in m.name.lower()) and ".db." not in m.class_name and "path" not in m.class_name and "google" not in m.class_name and m.return_type == "void" and len(m.params) == 1 and m.params[0] == "boolean")))))+"});"
54 | # crypto_methods = static.get_methods(
55 | # lambda m: (((("encrypt" in m.name.lower() or "decrypt" in m.name.lower()) and ("aes" in m.name.lower() or "rsa" in m.name.lower() or "byte" in m.name.lower() and "compress" in m.name.lower() and "string" in m.name.lower())) or ("encrypt" == m.name.lower() or "decrypt" == m.name.lower())) and ".db." not in m.class_name and 1 <= len(m.params) >= 3 and all([candid_methods(param) for param in m.params]) and candid_methods(m.return_type)))
56 |
57 | crypto_methods = static.get_methods(
58 | lambda m: (("encrypt" == m.name.lower() or "decrypt" in m.name.lower()) and ".db." not in m.class_name and 1 <= len(m.params) <= 4 and all([candid_methods(param) for param in m.params]) and candid_methods(m.return_type)))
59 | self.jscode += "Java.perform(function () {"+(
60 | "".join((m.to_frida(fh) for m in crypto_methods)))+"});"
61 |
62 | print(self.jscode)
63 | for file in ("general.js", "debug.js", "bypass_root_detection.js", "native.js", "java.js", "media.js", "fs.js", "pinning.js", "built_in_crypto.js"):
64 | with open("js/"+file) as f:
65 | self.jscode += f.read()
66 | # "java.lang.Object" in m or "JSONObject" in m or
67 |
68 | self.spawn = functools.partial(spawn_added, frida_device=self.frida, device=self.device,
69 | package=self.package, jscode=self.jscode, processes=dict(), fs=dict(), sessions=self.sessions)
70 | self.frida.on("spawn-added", self.spawn)
71 | self.frida.on("child-added", self.spawn)
72 |
73 | def run(self):
74 | self.frida.enable_spawn_gating()
75 |
76 | def stop(self):
77 | # self.frida.close()
78 | try:
79 | self.frida.disable_spawn_gating()
80 | self.frida.off("spawn-added", self.spawn)
81 | self.frida.off("child-added", self.spawn)
82 | for session in self.sessions:
83 | session.detach()
84 | except:
85 | pass
86 |
87 |
88 | def spawn_added(spawn, frida_device, device, package, jscode, processes, fs, sessions): # identifier pid
89 | # print("-------->"+spawn.identifier)
90 | print(spawn.identifier+"::::::"+package)
91 | if spawn.identifier.startswith(package) or spawn.identifier.startswith("com.android") or spawn.identifier.startswith("com.google.process") or spawn.identifier.startswith("com.google.android") or spawn.identifier in ("com.research.helper", "com.topjohnwu.magisk"):
92 | logging.debug("Process:"+str(spawn))
93 | processes[spawn.pid] = spawn.identifier
94 | if spawn.identifier.startswith(package+":") or spawn.identifier == package:
95 | try:
96 | session = frida_device.attach(spawn.pid)
97 | sessions.add(session)
98 | script = session.create_script(jscode)
99 | script.on("message", functools.partial(
100 | on_message, processes=processes, fs=fs, package=package))
101 | script.load()
102 | except:
103 | session.detach()
104 | # pass
105 | # sys.exit()
106 | # logging.debug(spawn.pid)
107 | else:
108 | pass
109 | # session.detach()
110 | try:
111 | frida_device.resume(spawn.pid)
112 | except:
113 | logging.debug("Errrr:"+str(spawn))
114 | pass
115 | else:
116 | for p in frida_device.enumerate_processes():
117 | if p.pid == spawn.pid:
118 | print("killed" + str(spawn.pid) + ":" + spawn.identifier)
119 | frida_device.resume(spawn.pid)
120 | frida_device.kill(spawn.pid)
121 | device.close_app(spawn.identifier)
122 |
123 |
124 | def on_message(message, data, package, processes, fs):
125 | stage = "-2" if os.path.exists("out/"+package+"/2nd.lock") else "-1"
126 | try:
127 | # print(message["payload"])
128 | # print(message)
129 | conn = json.loads(message["payload"])
130 | if "crypto" in conn:
131 | with open("out/"+package+"/crypt"+stage+".txt", "a") as f:
132 | c = json.loads(conn["crypto"])
133 | c["ts"] = time.time()
134 | f.write(json.dumps(c) + '\n')
135 | elif "key-iv" in conn:
136 | with open("out/"+package+"/key-iv"+stage+".txt", "a") as f:
137 | k = json.loads(conn["key-iv"])
138 | k["ts"] = time.time()
139 | f.write(json.dumps(k) + '\n')
140 | elif "deviceid" in conn:
141 | with open("out/"+package+"/id"+stage+".txt", "w") as f:
142 | f.write(str(conn["deviceid"]) + '\n')
143 | elif "fs" in conn:
144 | with open("out/"+package+"/fs"+stage+".txt", "a") as f:
145 | conn["fs"]["ts"] = time.time()
146 | f.write(json.dumps(conn["fs"]) + '\n')
147 | elif "media" in conn:
148 | with open("out/"+package+"/media"+stage+".txt", "a") as f:
149 | c = json.loads(conn["media"])
150 | ts = time.time()
151 | c["ts"] = ts
152 | print("adb exec-out screencap -p > out/" +
153 | package+"/media-"+str(ts)+".png")
154 | pp = subprocess.Popen(
155 | ["adb", "exec-out", "screencap", "-p"], stdout=subprocess.PIPE,)
156 | stdoutdata, stderrdata = pp.communicate()
157 | with open("out/"+package+"/media"+stage+"-"+str(ts)+".png", "wb") as fm:
158 | fm.write(stdoutdata)
159 | pp.wait()
160 | # c["ts"] = time.time()
161 | f.write(json.dumps(c) + '\n')
162 | else:
163 | t = "java" if "java" in conn else "native"
164 | conn[t]["pid"] = str(conn[t]["pid"])+"-"+processes[conn[t]["pid"]]
165 | conn[t]["ts"] = time.time()
166 | with open("out/"+package+"/conn"+stage+".txt", "a") as f:
167 | f.write(str(conn) + '\n')
168 | except:
169 | logging.debug("mm")
170 | logging.debug(message)
171 |
--------------------------------------------------------------------------------
/js/built_in_crypto.js:
--------------------------------------------------------------------------------
1 | setTimeout(function () {
2 |
3 | Java.perform(function () {
4 | // try {
5 | var cipher = Java.use('javax.crypto.Cipher');
6 | cipher.doFinal.overload().implementation = function () {
7 | var ret = this.doFinal();
8 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"doFinal\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[],\\"ret\\":\\"' + btoa(ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
9 | return ret;
10 | };
11 |
12 | cipher.doFinal.overload('[B').implementation = function (p0) {
13 | var ret = this.doFinal(p0);
14 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"doFinal\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\"],\\"ret\\":\\"' + btoa(ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
15 | return ret;
16 | };
17 |
18 | cipher.doFinal.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function (p0, p1) {
19 | var ret = this.doFinal(p0, p1);
20 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"doFinal\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + btoa(p1) + '\\"],\\"ret\\":\\"' + (ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
21 | return ret;
22 | };
23 |
24 | cipher.doFinal.overload('[B', 'int').implementation = function (p0, p1) {
25 | var ret = this.doFinal(p0, p1);
26 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"doFinal\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\"],\\"ret\\":\\"' + (ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
27 | return ret;
28 | };
29 |
30 | cipher.doFinal.overload('[B', 'int', 'int').implementation = function (p0, p1, p2) {
31 | var ret = this.doFinal(p0, p1, p2);
32 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"doFinal\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\",\\"' + (p2) + '\\"],\\"ret\\":\\"' + btoa(ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
33 | return ret;
34 | };
35 |
36 | cipher.doFinal.overload('[B', 'int', 'int', '[B').implementation = function (p0, p1, p2, p3) {
37 | var ret = this.doFinal(p0, p1, p2, p3);
38 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"doFinal\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\",\\"' + (p2) + '\\",\\"' + btoa(p3) + '\\"],\\"ret\\":\\"' + (ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
39 | return ret;
40 | };
41 |
42 | cipher.doFinal.overload('[B', 'int', 'int', '[B', 'int').implementation = function (p0, p1, p2, p3, p4) {
43 | var ret = this.doFinal(p0, p1, p2, p3, p4);
44 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"doFinal\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\",\\"' + (p2) + '\\",\\"' + btoa(p3) + '\\",\\"' + (p4) + '\\"],\\"ret\\":\\"' + (ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
45 | return ret;
46 | };
47 |
48 |
49 | cipher.update.overload('[B').implementation = function (p0) {
50 | var ret = this.update(p0);
51 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"update\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\"],\\"ret\\":\\"' + btoa(ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
52 | return ret;
53 | };
54 |
55 | cipher.update.overload('[B', 'int', 'int').implementation = function (p0, p1, p2) {
56 | var ret = this.update(p0, p1, p2);
57 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"update\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\",\\"' + (p2) + '\\"],\\"ret\\":\\"' + btoa(ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
58 | return ret;
59 | };
60 |
61 | cipher.update.overload('[B', 'int', 'int', '[B').implementation = function (p0, p1, p2, p3) {
62 | var ret = this.update(p0, p1, p2, p3);
63 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"update\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\",\\"' + (p2) + '\\",\\"' + btoa(p3) + '\\"],\\"ret\\":\\"' + (ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
64 | return ret;
65 | };
66 |
67 | cipher.update.overload('[B', 'int', 'int', '[B', 'int').implementation = function (p0, p1, p2, p3, p4) {
68 | var ret = this.update(p0, p1, p2, p3, p4);
69 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"update\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\",\\"' + (p2) + '\\",\\"' + btoa(p3) + '\\",\\"' + (p4) + '\\"],\\"ret\\":\\"' + (ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
70 | return ret;
71 | };
72 |
73 |
74 | cipher.update.overload('java.nio.ByteBuffer', 'java.nio.ByteBuffer').implementation = function (p0, p1) {
75 | var ret = this.update(p0, p1);
76 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"update\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + btoa(p1) + '\\"],\\"ret\\":\\"' + (ret) + '\\",\\"stackTrace\\":\\"' + btoa(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) + '\\"}"}');
77 | return ret;
78 | };
79 |
80 |
81 | /////////
82 |
83 |
84 | cipher.init.overload('int', 'java.security.Key').implementation = function (p0, p1) {
85 | this.init(p0, p1);
86 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"init-key\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"algorithm\\":\\"' + this.getAlgorithm() + '\\",\\"IV\\":\\"' + btoa(this.getIV()) + '\\",\\"args\\":[\\"' + p0 + '\\",\\"' + btoa(p1.getEncoded()) + '\\"],\\"ret\\":\\"\\"}"}');
87 | };
88 |
89 | cipher.init.overload('int', 'java.security.cert.Certificate').implementation = function (p0, p1) {
90 | this.init(p0, p1);
91 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"init-cert\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"algorithm\\":\\"' + this.getAlgorithm() + '\\",\\"IV\\":\\"' + btoa(this.getIV()) + '\\",\\"args\\":[\\"' + p0 + '\\",\\"' + btoa(p1.getEncoded()) + '\\"],\\"ret\\":\\"\\"}"}');
92 | };
93 | cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters').implementation = function (p0, p1, p2) {
94 | this.init(p0, p1, p2);
95 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"init-key\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"algorithm\\":\\"' + this.getAlgorithm() + '\\",\\"IV\\":\\"' + btoa(this.getIV()) + '\\",\\"args\\":[\\"' + p0 + '\\",\\"' + btoa(p1.getEncoded()) + '\\",\\"' + p2.getEncoded().getAlgorithm() + '\\"],\\"ret\\":\\"\\"}"}');
96 | };
97 | cipher.init.overload('int', 'java.security.Key', 'java.security.SecureRandom').implementation = function (p0, p1, p2) {
98 | this.init(p0, p1, p2);
99 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"init-key\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"algorithm\\":\\"' + this.getAlgorithm() + '\\",\\"IV\\":\\"' + btoa(this.getIV()) + '\\",\\"args\\":[\\"' + p0 + '\\",\\"' + btoa(p1.getEncoded()) + '\\",\\"' + "java.security.SecureRandom" + '\\"],\\"ret\\":\\"\\"}"}');
100 | };
101 |
102 | cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (p0, p1, p2) {
103 | this.init(p0, p1, p2);
104 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"init-key\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"algorithm\\":\\"' + this.getAlgorithm() + '\\",\\"IV\\":\\"' + btoa(this.getIV()) + '\\",\\"args\\":[\\"' + p0 + '\\",\\"' + btoa(p1.getEncoded()) + '\\",\\"' + "java.security.spec.AlgorithmParameterSpec" + '\\"],\\"ret\\":\\"\\"}"}');
105 | };
106 |
107 | cipher.init.overload('int', 'java.security.cert.Certificate', 'java.security.SecureRandom').implementation = function (p0, p1, p2) {
108 | this.init(p0, p1, p2);
109 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"init-cert\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"algorithm\\":\\"' + this.getAlgorithm() + '\\",\\"IV\\":\\"' + btoa(this.getIV()) + '\\",\\"args\\":[\\"' + p0 + '\\",\\"' + btoa(p1.getEncoded()) + '\\",\\"' + "java.security.SecureRandom" + '\\"],\\"ret\\":\\"\\"}"}');
110 | };
111 |
112 | cipher.init.overload('int', 'java.security.Key', 'java.security.AlgorithmParameters', 'java.security.SecureRandom').implementation = function (p0, p1, p2, p3) {
113 | this.init(p0, p1, p2, p3);
114 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"init-key\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"algorithm\\":\\"' + this.getAlgorithm() + '\\",\\"IV\\":\\"' + btoa(this.getIV()) + '\\",\\"args\\":[\\"' + p0 + '\\",\\"' + btoa(p1.getEncoded()) + '\\",\\"' + "java.security.AlgorithmParameters" + '\\",\\"' + "java.security.SecureRandom" + '\\"],\\"ret\\":\\"\\"}"}');
115 | };
116 |
117 | cipher.init.overload('int', 'java.security.Key', 'java.security.spec.AlgorithmParameterSpec', 'java.security.SecureRandom').implementation = function (p0, p1, p2, p3) {
118 | this.init(p0, p1, p2, p3);
119 | send('{"crypto":"{\\"class_name\\":\\"javax.crypto.Cipher\\",\\"method_name\\":\\"init-key\\",\\"hashcode\\":\\"' + this.hashCode() + '\\",\\"algorithm\\":\\"' + this.getAlgorithm() + '\\",\\"IV\\":\\"' + btoa(this.getIV()) + '\\",\\"args\\":[\\"' + p0 + '\\",\\"' + btoa(p1.getEncoded()) + '\\",\\"' + "java.security.spec.AlgorithmParameterSpec" + '\\",\\"' + "java.security.SecureRandom" + '\\"],\\"ret\\":\\"\\"}"}');
120 | };
121 |
122 | /////
123 | var IvParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
124 | IvParameterSpec.$init.overload('[B').implementation = function (p0) {
125 | var ret = this.$init(p0);
126 | send('{"key-iv":"{\\"class_name\\":\\"javax.crypto.spec.IvParameterSpec\\",\\"method_name\\":\\"$new\\",\\"args\\":[\\"' + btoa(p0) + '\\"],\\"ret\\":\\"\\"}"}');
127 | return ret;
128 | };
129 | var IvParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
130 | IvParameterSpec.$init.overload('[B', 'int', 'int').implementation = function (p0, p1, p2) {
131 | var ret = this.$init(p0, p1, p2);
132 | send('{"key-iv":"{\\"class_name\\":\\"javax.crypto.spec.IvParameterSpec\\",\\"method_name\\":\\"$new\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\",\\"' + (p2) + '\\"],\\"ret\\":\\"\\"}"}');
133 | return ret;
134 | };
135 | var SecretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
136 | SecretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (p0, p1) {
137 | var ret = this.$init(p0, p1);
138 | send('{"key-iv":"{\\"class_name\\":\\"javax.crypto.spec.SecretKeySpec\\",\\"method_name\\":\\"$new\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\"],\\"ret\\":\\"\\"}"}');
139 | return ret;
140 | };
141 | var SecretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
142 | SecretKeySpec.$init.overload('[B', 'int', 'int', 'java.lang.String').implementation = function (p0, p1, p2, p3) {
143 | var ret = this.$init(p0, p1, p2, p3);
144 | send('{"key-iv":"{\\"class_name\\":\\"javax.crypto.spec.SecretKeySpec\\",\\"method_name\\":\\"$new\\",\\"args\\":[\\"' + btoa(p0) + '\\",\\"' + (p1) + '\\",\\"' + (p2) + '\\",\\"' + p3 + '\\"],\\"ret\\":\\"\\"}"}');
145 | return ret;
146 | };
147 | });
148 |
149 | }, 0);
--------------------------------------------------------------------------------
/js/java.js:
--------------------------------------------------------------------------------
1 | setTimeout(function () {
2 | Java.perform(function () {
3 | var socket = Java.use('java.net.Socket');
4 | var datagramSocket = Java.use('java.net.DatagramSocket');
5 | var socketChannel = Java.use('java.nio.channels.SocketChannel');
6 | var datagramChannel = Java.use('java.nio.channels.DatagramChannel');
7 | var SettingsSecure = Java.use('android.provider.Settings$Secure');
8 | // var InetSocketAddress = Java.use('java.net.InetSocketAddress');
9 | // var sock = Java.use("java.net.Socket");
10 |
11 | // // socket constructors
12 |
13 | // //new Socket()
14 | // sock.$init.overload().implementation = function(){
15 | // console.log("new Socket() called");
16 | // // return this.$init.overload().call(this);
17 | // }
18 |
19 | // // new Socket(inetAddress, port)
20 | // sock.$init.overload("java.net.InetAddress", "int").implementation = function(inetAddress, port){
21 | // console.log("new Socket('"+inetAddress.toString()+"', "+port+") called");
22 | // // return this.$init.overload("java.net.InetAddress", "int").call(this, inetAddress, port);
23 | // }
24 |
25 | // // // new Socket(inetAddress address, port, localInetAddress, localPort)
26 | // // sock.$init.overload("java.net.InetAddress", "int","java.net.InetAddress", "int").implementation = function(inetAddress, port, localInet, localPort){
27 | // // console.log("new Socket(RemoteInet: '"+inetAddress.toString()+"', RemotePort"+port+", LocalInet: '"+localInet+"', LocalPort: "+localPort+") called");
28 | // // this.$init.overload("java.net.InetAddress", "int","java.net.InetAddress", "int").call(this, inetAddress, port);
29 | // // }
30 |
31 | // // // new Socket(Proxy)
32 | // // sock.$init.overload("java.net.Proxy").implementation = function(proxy){
33 | // // console.log("new Socket(Proxy: '"+proxy.toString()+"') called");
34 | // // this.$init.overload("java.net.Proxy").call(this, proxy);
35 | // // }
36 |
37 | // // // new Socket(SocketImp)
38 | // // sock.$init.overload("java.net.SocketImpl").implementation = function(si){
39 | // // console.log("new Socket(SocketImpl: '"+si.toString()+"') called");
40 | // // this.$init.overload("java.net.SocketImpl").call(this, si);
41 | // // }
42 |
43 | // // // new Socket(host, port, localInetAddr, localPort)
44 | // // sock.$init.overload("java.lang.String", "int", "java.net.InetAddress", "int").implementation = function(host,port, localInetAddress, localPort){
45 | // // console.log("new Socket(Host: '"+host+"', RemPort: "+port+", LocalInet: '"+localInetAddress+"', localPort: "+localPort+") called");
46 | // // this.$init.overload("java.lang.String", "int", "java.net.InetAddress", "int").call(this, si);
47 | // // }
48 |
49 | var inetSockAddrWrap = Java.use("java.net.InetSocketAddress");
50 | try {
51 | var sfs2x = Java.use('sfs2x.client.SmartFox');
52 | sfs2x.connect.overload('java.lang.String', 'int').implementation = function (addr, port) {
53 | if (addr != null && port != -1) {
54 | send('{"java":{"protocol":"tcp","function":"SmartFox::connect(String, int)","pid":' + Process.id + ',"address":"' + addr + ":" + port.toString() + '"}}');
55 | //send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()))
56 | }
57 | return this.connect(addr, port)
58 | };
59 | } catch (error) { }
60 |
61 | socket.connect.overload('java.net.SocketAddress', 'int').implementation = function (addr, timeout) {
62 | // var ret = this.connect(addr, timeout);
63 | if (addr.toString().endsWith(":443")) {
64 | console.log(addr.toString())
65 | var inetSockAddrImpl = inetSockAddrWrap.$new(proxy_addr4, 8080)
66 | var ret = this.connect(inetSockAddrImpl, timeout);
67 | console.log(addr.toString());
68 | } else if (addr.toString().endsWith("127.0.0.1:27042")){
69 | var inetSockAddrImpl = inetSockAddrWrap.$new("127.0.0.1", 1)
70 | send('{"java":{"protocol":"tcp","function":"Socket::connect(SocketAddress, int)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.getLocalSocketAddress() + '"}}');
71 | var ret = this.connect(inetSockAddrImpl, timeout);
72 | } else {
73 | var ret = this.connect(addr, timeout);
74 | }
75 |
76 | // console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
77 |
78 | if (JavaConnectionPool[addr.toString().replace(/^.*\//, '')] == undefined) {
79 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = [String(this.getLocalSocketAddress()).replace(/^.*\//, '')]
80 | } else {
81 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')].push(String(this.getLocalSocketAddress()).replace(/^.*\//, ''));
82 | }
83 |
84 | // JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = String(this.getLocalSocketAddress()).replace(/^.*\//, '');
85 | send('{"java":{"protocol":"tcp","function":"Socket::connect(SocketAddress, int)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.getLocalSocketAddress() + '"}}');
86 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
87 | return ret;
88 | };
89 |
90 | socket.connect.overload('java.net.SocketAddress').implementation = function (addr) {
91 | // var ret = this.connect(addr);
92 | if (addr.toString().endsWith(":443")) {
93 | var inetSockAddrImpl = inetSockAddrWrap.$new(proxy_addr4, 8080)
94 | var ret = this.connect(inetSockAddrImpl);
95 | console.log(addr.toString());
96 | // } else if (addr.toString().endsWith("127.0.0.1:27042")){
97 | // var inetSockAddrImpl = inetSockAddrWrap.$new("127.0.0.1", 1)
98 | // send('{"java":{"protocol":"tcp","function":"Socket::connect(SocketAddress, int)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.getLocalSocketAddress() + '"}}');
99 | // var ret = this.connect(inetSockAddrImpl);
100 | } else {
101 | var ret = this.connect(addr);
102 | }
103 |
104 | if (JavaConnectionPool[addr.toString().replace(/^.*\//, '')] == undefined) {
105 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = [String(this.getLocalSocketAddress()).replace(/^.*\//, '')]
106 | } else {
107 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')].push(String(this.getLocalSocketAddress()).replace(/^.*\//, ''));
108 | }
109 | // JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = String(this.getLocalSocketAddress()).replace(/^.*\//, '');
110 | send('{"java":{"protocol":"tcp","function":"Socket::connect(SocketAddress)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.getLocalSocketAddress() + '"}}');
111 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
112 | return ret;
113 | };
114 | datagramSocket.connect.overload('java.net.InetAddress', 'int').implementation = function (addr, timeout) {
115 | var ret = this.connect(addr, timeout);
116 | if (JavaConnectionPool[addr.toString().replace(/^.*\//, '')] == undefined) {
117 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = [String(this.getLocalSocketAddress()).replace(/^.*\//, '')]
118 | } else {
119 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')].push(String(this.getLocalSocketAddress()).replace(/^.*\//, ''));
120 | }
121 | // JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = String(this.getLocalSocketAddress()).replace(/^.*\//, '');
122 | send('{"java":{"protocol":"tcp","function":"DatagramSocket::connect(SocketAddress, int)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.getLocalSocketAddress() + '"}}');
123 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
124 | return ret;
125 | };
126 | datagramSocket.connect.overload('java.net.SocketAddress').implementation = function (addr) {
127 | var ret = this.connect(addr);
128 | if (JavaConnectionPool[addr.toString().replace(/^.*\//, '')] == undefined) {
129 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = [String(this.getLocalSocketAddress()).replace(/^.*\//, '')]
130 | } else {
131 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')].push(String(this.getLocalSocketAddress()).replace(/^.*\//, ''));
132 | }
133 | // JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = String(this.getLocalSocketAddress()).replace(/^.*\//, '');
134 | send('{"java":{"protocol":"tcp","function":"DatagramSocket::connect(SocketAddress)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.getLocalSocketAddress() + '"}}');
135 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
136 | return ret;
137 | };
138 | datagramSocket.send.implementation = function (dp) {
139 | var ret = this.send(dp);
140 | if (JavaConnectionPool[dp.getSocketAddress().toString().replace(/^.*\//, '')] == undefined) {
141 | JavaConnectionPool[dp.getSocketAddress().toString().replace(/^.*\//, '')] = [String(this.getLocalSocketAddress()).replace(/^.*\//, '')]
142 | } else {
143 | JavaConnectionPool[dp.getSocketAddress().toString().replace(/^.*\//, '')].push(String(this.getLocalSocketAddress()).replace(/^.*\//, ''));
144 | }
145 | // JavaConnectionPool[dp.getSocketAddress().toString().replace(/^.*\//, '')] = String(this.getLocalSocketAddress()).replace(/^.*\//, '');
146 | send('{"java":{"protocol":"udp","function":"DatagramSocket::send","pid":' + Process.id + ',"address":"' + dp.getSocketAddress().toString() + '","local_address":"' + this.getLocalSocketAddress() + '"}}');
147 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
148 | return ret;
149 | };
150 | datagramSocket.receive.implementation = function (dp) {
151 | var ret = this.receive(dp);
152 | if (JavaConnectionPool[dp.getSocketAddress().toString().replace(/^.*\//, '')] == undefined) {
153 | JavaConnectionPool[dp.getSocketAddress().toString().replace(/^.*\//, '')] = [String(this.getLocalSocketAddress()).replace(/^.*\//, '')]
154 | } else {
155 | JavaConnectionPool[dp.getSocketAddress().toString().replace(/^.*\//, '')].push(String(this.getLocalSocketAddress()).replace(/^.*\//, ''));
156 | }
157 | // JavaConnectionPool[dp.getSocketAddress().toString().replace(/^.*\//, '')] = String(this.getLocalSocketAddress()).replace(/^.*\//, '');
158 | send('{"java":{"protocol":"udp","function":"DatagramSocket::receive","pid":' + Process.id + ',"address":"' + dp.getSocketAddress().toString() + '","local_address":"' + this.getLocalSocketAddress() + '"}}');
159 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
160 | return ret;
161 | };
162 | socketChannel.connect.implementation = function (addr) {
163 | var ret = this.connect(addr);
164 | if (JavaConnectionPool[addr.toString().replace(/^.*\//, '')] == undefined) {
165 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = [String(this.socket().getLocalSocketAddress()).replace(/^.*\//, '')]
166 | } else {
167 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')].push(String(this.socket().getLocalSocketAddress()).replace(/^.*\//, ''));
168 | }
169 |
170 | // JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = String(this.getLocalSocketAddress()).replace(/^.*\//, '');
171 | send('{"java":{"protocol":"tcp","function":"SocketChannel::connect(SocketAddress)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.socket().getLocalSocketAddress() + '"}}');
172 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
173 | return ret;
174 | };
175 | socketChannel.open.overload('java.net.SocketAddress').implementation = function (addr) {
176 | var ret = this.open(addr);
177 | if (JavaConnectionPool[addr.toString().replace(/^.*\//, '')] == undefined) {
178 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = [String(this.socket().getLocalSocketAddress()).replace(/^.*\//, '')]
179 | } else {
180 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')].push(String(this.socket().getLocalSocketAddress()).replace(/^.*\//, ''));
181 | }
182 | // JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = String(this.socket().getLocalSocketAddress()).replace(/^.*\//, '');
183 | send('{"java":{"protocol":"tcp","function":"SocketChannel::open(SocketAddress)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.socket().getLocalSocketAddress() + '"}}');
184 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
185 | return ret;
186 | };
187 | datagramChannel.connect.implementation = function (addr) {
188 | var ret = this.connect(addr);
189 | if (JavaConnectionPool[addr.toString().replace(/^.*\//, '')] == undefined) {
190 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = [String(this.socket().getLocalSocketAddress()).replace(/^.*\//, '')]
191 | } else {
192 | JavaConnectionPool[addr.toString().replace(/^.*\//, '')].push(String(this.socket().getLocalSocketAddress()).replace(/^.*\//, ''));
193 | }
194 | // JavaConnectionPool[addr.toString().replace(/^.*\//, '')] = String(this.socket().getLocalSocketAddress()).replace(/^.*\//, '');
195 | send('{"java":{"protocol":"tcp","function":"DatagramChannel::connect(SocketAddress)","pid":' + Process.id + ',"address":"' + addr.toString() + '","local_address":"' + this.socket().getLocalSocketAddress() + '"}}');
196 | send('{"deviceid":"' + SettingsSecure.getString(Java.use('android.app.ActivityThread').currentApplication().getApplicationContext().getContentResolver(), 'android_id') + '"}');
197 | return ret;
198 | };
199 | });
200 | }, 0);
--------------------------------------------------------------------------------
/device.py:
--------------------------------------------------------------------------------
1 | import hashlib
2 | import json
3 | import logging
4 | import math
5 | import os
6 | import subprocess
7 | import sys
8 | import time
9 |
10 | import frida
11 | from com.dtmilano.android.adb.adbclient import AdbClient
12 | from com.dtmilano.android.viewclient import ViewClient
13 | from uiautomator import device
14 |
15 | import exceptions
16 | import interactor
17 | import timeout
18 |
19 | # adb shell ime list -s -a
20 | # adb shell ime set com.apedroid.hwkeyboardhelperfree/.HWKeyboardHelperIME
21 |
22 |
23 | def get_active_devices():
24 | devices = list()
25 | for d in AdbClient().getDevices():
26 | transport_id = [i for i in d.qualifiers if i.startswith(
27 | 'transport_id:')][0][13:]
28 | devices.append(Device(AdbClient(serialno=d.serialno), transport_id))
29 | logging.debug(d.serialno)
30 | if devices == []:
31 | raise exceptions.DeviceNotFound
32 | return devices
33 |
34 |
35 | class Device:
36 | def __init__(self, d, transport_id):
37 |
38 | self.d = d
39 | self.transport_id = transport_id
40 | self.shell = lambda c: self.d.shell(c).strip()
41 | self.alive = True
42 | self.info = {}
43 | self.update_info()
44 | self.frida = list(d for d in frida.get_device_manager(
45 | ).enumerate_devices() if d.id in (self.d.serialno, self.info["ro.serialno"]))[0]
46 | self.close_all_apps()
47 | self.vc = ViewClient(*(self.d, self.d.serialno))
48 | self.display = Display(self)
49 | self.permissions = self.get_device_permissions()
50 |
51 | def second(self):
52 | self.frida = list(d for d in frida.get_device_manager().enumerate_devices(
53 | ) if d.id in (self.d.serialno, self.info["ro.serialno"]))[0]
54 |
55 | def get_device_permissions(self):
56 | return set(p[11:] for p in self.shell("pm list permissions").splitlines() if p.startswith("permission:"))
57 |
58 | def get_app_permissions(self, package):
59 | dumpsys = self.shell("dumpsys package "+package).splitlines()
60 | l = {"android.permission.SYSTEM_ALERT_WINDOW"}
61 | a = str()
62 | f = False
63 |
64 | for i, r in enumerate(dumpsys):
65 | if r.startswith((" "*6)+"android.service.notification.NotificationListenerService") and dumpsys[i+1].startswith(" "*8) and dumpsys[i+1].endswith("BIND_NOTIFICATION_LISTENER_SERVICE"):
66 | a += "cmd notification allow_listener {};".format(
67 | dumpsys[i+1][8:].split(' ')[1])
68 | break
69 | for i, r in enumerate(dumpsys):
70 | if r.startswith((" "*6)+"android.accessibilityservice.AccessibilityService") and dumpsys[i+1].startswith(" "*8) and dumpsys[i+1].endswith("BIND_ACCESSIBILITY_SERVICE"):
71 | a += "settings put secure enabled_accessibility_services {};".format(
72 | dumpsys[i+1][8:].split(' ')[1])
73 | break
74 | for i in dumpsys:
75 | if i.startswith((" "*6)+"runtime permissions"):
76 | f = True
77 | continue
78 | if f and i.startswith(" "*8):
79 | if ' ' in i[8:]:
80 | l.add(i[8:].split(': ')[0])
81 | else:
82 | l.add(i[8:])
83 | else:
84 | f = False
85 | # print(l)
86 | return l, a
87 | # for i in self.shell("dumpsys package "+package).splitlines():
88 | # if i.startswith((" "*4)+"requested permissions"):
89 | # f = True
90 | # continue
91 | # if f and i.startswith(" "*6):
92 | # if ' ' in i[6:]:
93 | # l.add(i[6:].split(': ')[0])
94 | # else:
95 | # l.add(i[6:])
96 | # else:
97 | # f = False
98 | # return l
99 |
100 | def grant_app_permissions(self, package, perms=set(), service_name=str(), service=True):
101 | _perms = set()
102 | if len(perms) == 0:
103 | _perms, _service_name = self.get_app_permissions(package)
104 | else:
105 | _perms = perms
106 | _service_name = service_name
107 | for perm in _perms:
108 | self.shell("pm grant "+package+" "+perm)
109 | if _service_name:
110 | self.shell(_service_name)
111 | return _perms, _service_name
112 |
113 | def update_info(self):
114 | serialno = self.shell("getprop ro.serialno")
115 | if len(serialno) != 0:
116 | self.info["ro.serialno"] = serialno
117 |
118 | def is_alive(self):
119 | try:
120 | with timeout.timeout(seconds=20):
121 | if self.shell("echo alive") == "alive":
122 | self.alive = True
123 | return True
124 | else:
125 | self.alive = False
126 | return False
127 | except:
128 | self.alive = False
129 | return False
130 |
131 | def close_app(self, package):
132 | try:
133 | if self.shell("pm clear "+package) == "Success":
134 | return True
135 | else:
136 | return False
137 | except:
138 | return False
139 |
140 | def close_all_apps(self):
141 | packages = self.get_paused_activites()
142 | print(packages)
143 | if self.get_current_activity() != None:
144 | packages.add(self.get_current_activity())
145 | # packages.discard('com.android.launcher3/.lineage.LineageLauncher')
146 | packages.discard(
147 | 'com.google.android.apps.nexuslauncher/.NexusLauncherActivity')
148 | packages.discard('com.google.android.apps.nexuslauncher/com.android.launcher3.settings.SettingsActivity')
149 | # packages.add('org.lineageos.jelly')
150 | # packages.add('com.android.chrome')
151 | print(packages)
152 | for package in packages:
153 | p = package.split("/")[0]
154 | if p == "com.google.android.apps.nexuslauncher":
155 | self.shell("am force-stop "+p)
156 | elif self.shell("pm clear "+p) != "Success":
157 | return False
158 | return True
159 |
160 | def close_paused_apps(self):
161 | for package in self.get_paused_activites():
162 | p = package.split("/")[0]
163 | if p == "com.google.android.apps.nexuslauncher":
164 | self.shell("am force-stop "+p)
165 | elif self.shell("pm clear "+p) != "Success":
166 | return False
167 | return True
168 |
169 | def uninstall_3rd_party_apps(self):
170 | self.shell("su -c killall tcpdump")
171 | packages = self.shell('pm list packages -3 | cut -c9- | grep -Ev "(com.apedroid.hwkeyboardhelperfree|com.github.shadowsocks|com.research.helper|org.proxydroid|com.fakemygps.android|org.meowcat.edxposed.manager|edu.berkeley.icsi.haystack|com.topjohnwu.magisk|app.greyshirts.sslcapture|tw.fatminmin.xposed.minminguard|com.cofface.ivader)"')
172 | for package in packages.splitlines():
173 | self.uninstall_app(package)
174 |
175 | def is_internet_available(self):
176 | # if "success" in self.shell(
177 | # "echo \"GET /success.txt\" | nc detectportal.firefox.com 80"):
178 | # if "success" in self.shell("curl --connect-timeout 2 detectportal.firefox.com/success.txt"):
179 | if "ttl=" in self.shell("ping -c 1 1.1.1.1"):
180 | return True
181 | return False
182 |
183 | def wait_if_internet_isnt_available(self):
184 | while self.is_internet_available() == False:
185 | logging.warning('Internet is not available, please wait')
186 | time.sleep(2)
187 |
188 | def is_app_crashed(self, app):
189 | current_focus = self.shell(
190 | "dumpsys activity activities | grep -E \"mCurrentFocus.+Application Error:.+"+app+"\"").split()
191 | if len(current_focus) > 0:
192 | return True
193 | else:
194 | return False
195 |
196 | def is_app_hangs(self, app):
197 | current_focus = self.shell(
198 | "dumpsys activity activities | grep -E \"mCurrentFocus.+Application Not Responding:.+"+app+"\"").split()
199 | if len(current_focus) > 0:
200 | return True
201 | else:
202 | return False
203 |
204 | def get_current_activity(self):
205 | # time.sleep(0.5)
206 | m_resumed_activity = self.shell(
207 | "dumpsys activity activities | grep mResumedActivity").split()
208 | print("00s00")
209 | print(m_resumed_activity)
210 | print("00s01")
211 | i = 0
212 | if len(m_resumed_activity) > 0:
213 | print("00s01-1")
214 | if m_resumed_activity in (["Can't", 'find', 'service:', 'activity']) or m_resumed_activity[0] == "Can't":
215 | print("00s01-2")
216 | os.system('kill -9 {pid}'.format(pid=os.getpid()))
217 |
218 | while m_resumed_activity in ([], ['mHoldScreenWindow=null']):
219 | if i > 8:
220 | return None
221 | break
222 | i += 1
223 | print(m_resumed_activity)
224 | print("00s11")
225 | # self.shell('input keyevent KEYCODE_POWER')
226 | self.shell('input keyevent KEYCODE_HOME')
227 | time.sleep(3)
228 | self.d.wake()
229 | m_resumed_activity = self.shell(
230 | "dumpsys activity activities | grep mResumedActivity").split()
231 | if m_resumed_activity == []:
232 | m_resumed_activity = self.shell(
233 | "dumpsys window windows | grep mHoldScreenWindow").split()
234 | if m_resumed_activity in ([], ['mHoldScreenWindow=null']):
235 | m_resumed_activity = self.shell(
236 | "dumpsys window windows | grep mActivityRecord | grep -v com.android.launcher3").split()
237 | print(m_resumed_activity)
238 | if len(m_resumed_activity) > 0:
239 | if m_resumed_activity in (["Can't", 'find', 'service:', 'activity']) or m_resumed_activity[0] == "Can't":
240 | os.system('kill -9 {pid}'.format(pid=os.getpid()))
241 | # logging.debug("m_resumed_activity")
242 | # logging.debug(m_resumed_activity)
243 |
244 | # while m_resumed_activity == []:
245 | # logging.debug(m_resumed_activity)
246 | # time.sleep(0.5)
247 | # m_resumed_activity = self.shell(
248 | # "dumpsys activity activities | grep mResumedActivity").split()
249 | # logging.debug(m_resumed_activity)
250 | print(len(m_resumed_activity))
251 | if len(m_resumed_activity) > 2 and m_resumed_activity[0].startswith("mActivityRecord"):
252 | print(m_resumed_activity[2])
253 | return m_resumed_activity[2]
254 | if len(m_resumed_activity) > 4:
255 | print(m_resumed_activity[3])
256 | return m_resumed_activity[3]
257 |
258 | def get_paused_activites(self):
259 | return set(line.split()[3] for line in self.shell("dumpsys activity activities | grep mLastPausedActivity").splitlines())
260 |
261 | def get_package_window_hash(self, pkg):
262 | packages = self.get_paused_activites()
263 | if self.get_current_activity() != None:
264 | packages.add(self.get_current_activity())
265 | for package in packages:
266 | if package.startswith(pkg):
267 | return hashlib.sha256(self.shell("dumpsys window | grep "+pkg).encode("utf-8")).hexdigest()
268 |
269 | def pull(self, src, dst="./"):
270 | # logging.debug(src)
271 | final_path = dst+"/"+src.split("/").pop()
272 | try:
273 | apk_device_hash = self.shell("sha256sum"+" "+src).split()[0]
274 | logging.debug(apk_device_hash)
275 | logging.debug(src)
276 | except:
277 | return False
278 |
279 | if os.path.exists(final_path):
280 | with open(final_path, "rb") as f:
281 | if hashlib.sha256(f.read()).hexdigest() == apk_device_hash:
282 | return True
283 | p = subprocess.Popen(
284 | ["adb", "-t", self.transport_id, "pull", src, dst],)
285 | # stdout=subprocess.PIPE,)
286 | p.wait()
287 | with open(final_path, "rb") as f:
288 | if hashlib.sha256(f.read()).hexdigest() != apk_device_hash:
289 | return False
290 | return True
291 |
292 | def push(self, src, dst):
293 | # src_name = src.split("/").pop()
294 | with open(src, "rb") as f:
295 | fhash = hashlib.sha256(f.read()).hexdigest()
296 | p = subprocess.Popen(
297 | ["adb", "-t", self.transport_id, "push", src, dst],)
298 | # stdout=subprocess.PIPE,)
299 | p.wait()
300 | try:
301 | apk_device_hash = self.shell(
302 | "sha256sum"+" "+dst+src.split("/").pop()).split()[0]
303 | except:
304 | return False
305 | if fhash != apk_device_hash:
306 | return False
307 | return True
308 |
309 | def start_capture(self, package):
310 | self.shell("rm -f /sdcard/*")
311 | self.shell("rm -f /data/local/tmp/*.pcap")
312 | return (subprocess.Popen(
313 | [
314 | "adb",
315 | "shell",
316 | "su",
317 | "-c",
318 | "tcpdump",
319 | "port not 5555",
320 | "-i",
321 | "wlan0",
322 | "-w",
323 | "/data/local/tmp/" + package + ".pcap",
324 | ],
325 | stdout=subprocess.DEVNULL,
326 | stderr=subprocess.DEVNULL,
327 | ), subprocess.Popen(
328 | [
329 | "mitmdump",
330 | "-w",
331 | "out/"+package+"/mitmdump",
332 | "--anticomp",
333 | "--listen-port",
334 | "8080",
335 | ],
336 | stdout=subprocess.DEVNULL,
337 | stderr=subprocess.DEVNULL,
338 | ))
339 |
340 | def file_readable(self, path):
341 | if (self.shell("if [ -r \""+path+"\" ] && [ -f \""+path+"\" ]; then echo True;fi") == "True"):
342 | return True
343 | else:
344 | return False
345 |
346 | def store_files(self, package, stage):
347 | outpath = "out/"+package+"/"
348 | filelines = []
349 | for f in os.listdir(outpath):
350 | if f.startswith('fs-') and f.endswith('.txt'):
351 | with open(outpath+f, 'r') as _f:
352 | filelines += _f.readlines()
353 | recordes = [json.loads(i) for i in filelines if json.loads(i)[
354 | "function"] in ("open", "rename")]
355 | paths = ((i["path"] if i[
356 | "function"] == "open" else i["destination"]) for i in recordes)
357 |
358 | for p in paths:
359 |
360 | if self.file_readable(p):
361 | os.makedirs(outpath+"/files-"+str(stage) + "/" +
362 | os.path.dirname(p), exist_ok=True)
363 | self.pull(p, outpath+"/files-"+str(stage) +
364 | "/"+os.path.dirname(p)+"/")
365 |
366 | def stop_capture(self, p, mitm, package):
367 | p.kill()
368 | mitm.kill()
369 | # parents_of_dead_kids=$(ps -ef | grep [d]efunct | awk '{print $3}' | sort | uniq | egrep -v '^1$'); echo "$parents_of_dead_kids" | xargs kill
370 | self.shell("su -c killall tcpdump")
371 | # logging.debug("x")
372 | self.pull("/data/local/tmp/" + package+".pcap", "out/"+package)
373 | subprocess.Popen(
374 | [
375 | "pcapfix",
376 | "out/" + package + "/"+package + ".pcap",
377 | "-o",
378 | "out/" + package + "/clean.pcap",
379 | ],
380 | stdout=subprocess.DEVNULL,
381 | stderr=subprocess.DEVNULL,
382 | ).wait()
383 | # tmp
384 | os.system(
385 | "echo $(ps -ef | grep [d]efunct | awk '{print $3}' | sort | uniq | grep mitmdump| egrep -v '^1$') | xargs kill -9")
386 |
387 | def install_app(self, package, output="out/", reinstall=True): # multiple try
388 | if os.path.exists(output + package+"/"+package + ".pcap") or os.path.exists("out/" + package + ".fail"):
389 | return False
390 | self.shell("su -c 'pm disable com.android.chrome;pm disable com.google.android.youtube;pm disable com.google.android.calendar;pm disable com.google.android.apps.docs;pm disable com.google.android.apps.customization.pixel;pm disable com.google.android.gm;pm disable com.google.android.apps.tycho;pm disable com.google.android.calculator;pm disable com.google.android.markup;pm disable com.android.safetyregulatoryinfo;pm disable com.google.android.apps.wallpaper.pixel;pm disable com.google.android.videos;pm disable com.google.android.apps.youtube.music;pm disable com.google.pixel.dynamicwallpapers;pm disable com.google.ar.core;pm disable com.google.android.projection.gearhead;pm disable com.google.android.apps.tips;pm disable com.google.android.googlequicksearchbox;pm disable com.google.android.apps.safetyhub'")
391 | if self.is_app_exist(package) and reinstall:
392 | self.uninstall_app(package)
393 | elif self.is_app_exist(package) and reinstall == False:
394 | self.shell("su -c pm disable {package};".format(package=package))
395 | return True
396 | self.shell(
397 | "content insert --uri content://settings/system --bind name:s:accelerometer_rotation --bind value:i:0")
398 | if os.path.exists(output + package + "/base.apk"): # debug
399 | apks = list(output + package + "/"+f for f in os.listdir(
400 | output + package) if f.endswith('.apk'))
401 | obbs = list(output + package + "/"+f for f in os.listdir(
402 | output + package) if f.endswith('.obb'))
403 | if apks:
404 | p = subprocess.Popen(
405 | ["adb", "-t", self.transport_id,"install-multiple" , "-g"]+apks, stdout=subprocess.PIPE,)
406 | p.wait()
407 | try:
408 | if "Success" in str(p.communicate()[0]):
409 | if obbs:
410 | self.shell("mkdir -p /sdcard/obb/"+package)
411 | print(obbs)
412 | if all([self.push(obb, "/sdcard/obb/"+package+"/") for obb in obbs]):
413 | self.shell("mv /sdcard/obb/{} /sdcard/Android/obb/".format(package))
414 | self.shell(
415 | "su -c pm disable {package};".format(package=package))
416 | return True
417 | else:
418 | return False
419 | self.shell(
420 | "su -c pm disable {package};".format(package=package))
421 | return True
422 | except:
423 | return False
424 | else:
425 | if os.path.exists(output + package + ".fail"):
426 | return False
427 | gp = interactor.GooglePlay(self)
428 | for _ in range(0, 2):
429 | gpi = gp.install(package)
430 | if gpi == None or gpi == False:
431 | with open(output + package + ".fail", 'w') as fp:
432 | pass
433 | return False
434 | elif gpi == True:
435 | self.shell(
436 | "su -c pm disable {package};".format(package=package))
437 | return True
438 | pass
439 | pass
440 |
441 | def uninstall_app(self, package):
442 | self.shell(
443 | 'for file in $(find /sdcard/ -maxdepth 1 ); do if [ $file != "/sdcard/DCIM" ] && [ $file != "/sdcard/" ]; then rm -rf "$file" ;fi;done;rm -rf /sdcard/*\ *')
444 | if self.is_app_exist(package) and self.shell("pm uninstall {package}".format(package=package)) == "Success":
445 | return True
446 | return False
447 |
448 | def is_app_open(self, package):
449 | try:
450 | current_activity = self.get_current_activity()
451 | print(current_activity)
452 | if self.get_current_activity() and (current_activity.startswith(package) or current_activity.startswith("com.google.android.gms/.common") or current_activity in ["com.google.android.gms/.signin.activity.ConsentActivity", "com.google.android.gms/.auth.uiflows.consent.BrowserConsentActivity", "com.google.android.gms/.auth.uiflows.addaccount.AccountIntroActivity", "com.android.permissioncontroller/.permission.ui.ReviewPermissionsActivity"]):
453 | return True
454 | return False
455 | except:
456 | return False
457 |
458 | def run_app(self, package, close=True):
459 | if close:
460 | self.close_all_apps()
461 | self.shell(
462 | "su -c pm enable {package};monkey -p {package} --pct-touch 100 1".format(package=package))
463 | # print("----------")
464 | time.sleep(1)
465 | if not self.is_app_open(package):
466 | return True
467 | else:
468 | return False
469 |
470 | def is_app_exist(self, package):
471 | for exsited_package in self.shell("cmd package list packages "+package).splitlines():
472 | if exsited_package.split(":", 1)[1] == package:
473 | return True
474 | return False
475 |
476 | def store_app(self, package, output="out/"):
477 | if os.path.exists(output + package+"/base.apk"):
478 | return
479 | if not os.path.exists(output + package):
480 | os.makedirs(output + package)
481 | obbs = list(map(lambda x: "/sdcard/Android/obb/"+package+"/"+x,
482 | self.shell("ls -1 /sdcard/Android/obb/"+package+"/").split("\n")))
483 | if "No such" in obbs[0]:
484 | obbs.clear()
485 | apks = list(map(lambda x: x[8:], self.shell(
486 | "pm path "+package).split("\n")))
487 | for i in obbs+apks:
488 | while True:
489 | try:
490 | with timeout.timeout(seconds=120):
491 | logging.debug("t2")
492 | print(i, output + package)
493 | if self.pull(i, output + package) == True:
494 | break
495 | except:
496 | subprocess.Popen(["killall", "adb"],
497 | stdout=subprocess.PIPE,).wait()
498 | subprocess.Popen(
499 | ["rm", "-rf", output + package], stdout=subprocess.PIPE,).wait()
500 | # sys.exit()
501 | os.system('kill -9 {pid}'.format(pid=os.getpid()))
502 |
503 | def start_interaction(self, package, stage, analysis_time):
504 | # try:
505 | if not self.is_app_open(package):
506 | self.run_app(package)
507 | interaction = interactor.App(self, package, stage, analysis_time)
508 | interaction.smart()
509 | # except:
510 | # with open("out/"+package+"/animat.txt", "a") as f:
511 | # f.write(str(stage)+"-"+str(int(time.time()))+"\n")
512 | # return False
513 | # # The views are being refreshed too frequently to dump.
514 | # logging.debug("xx")
515 |
516 |
517 | class Display:
518 | def __init__(self, device):
519 | self.density = int(device.shell("wm density").split(" ")[-1])
520 | (x, y) = device.shell("wm size").split(" ")[-1].split("x")
521 | self.x = int(x)
522 | self.y = int(y)
523 | self.statusbar = math.ceil(self.density/160)*24
524 |
525 |
526 | # adb shell content query --uri content://com.android.contacts/data --projection display_name:data1:data4:contact_id
527 | # adb shell "su -c 'sqlite3 /data/data/com.android.providers.contacts/databases/calllog.db \"select * from calls\"'"
528 |
--------------------------------------------------------------------------------
/js/pinning.js:
--------------------------------------------------------------------------------
1 | setTimeout(function () {
2 | Java.perform(function () {
3 | //console.log("---");
4 | //console.log("Unpinning Android app...");
5 |
6 | // HttpsURLConnection
7 | try {
8 | const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
9 | HttpsURLConnection.setDefaultHostnameVerifier.implementation = function (hostnameVerifier) {
10 | //console.log(' --> Bypassing HttpsURLConnection (setDefaultHostnameVerifier)');
11 | return; // Do nothing, i.e. don't change the hostname verifier
12 | };
13 | //console.log('[+] HttpsURLConnection (setDefaultHostnameVerifier)');
14 | } catch (err) {
15 | //console.log('[ ] HttpsURLConnection (setDefaultHostnameVerifier)');
16 | }
17 | try {
18 | const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
19 | HttpsURLConnection.setSSLSocketFactory.implementation = function (SSLSocketFactory) {
20 | //console.log(' --> Bypassing HttpsURLConnection (setSSLSocketFactory)');
21 | return; // Do nothing, i.e. don't change the SSL socket factory
22 | };
23 | //console.log('[+] HttpsURLConnection (setSSLSocketFactory)');
24 | } catch (err) {
25 | //console.log('[ ] HttpsURLConnection (setSSLSocketFactory)');
26 | }
27 | try {
28 | const HttpsURLConnection = Java.use("javax.net.ssl.HttpsURLConnection");
29 | HttpsURLConnection.setHostnameVerifier.implementation = function (hostnameVerifier) {
30 | //console.log(' --> Bypassing HttpsURLConnection (setHostnameVerifier)');
31 | return; // Do nothing, i.e. don't change the hostname verifier
32 | };
33 | //console.log('[+] HttpsURLConnection (setHostnameVerifier)');
34 | } catch (err) {
35 | //console.log('[ ] HttpsURLConnection (setHostnameVerifier)');
36 | }
37 |
38 | // SSLContext
39 | try {
40 | const X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
41 | const SSLContext = Java.use('javax.net.ssl.SSLContext');
42 |
43 | const TrustManager = Java.registerClass({
44 | // Implement a custom TrustManager
45 | name: 'dev.asd.test.TrustManager',
46 | implements: [X509TrustManager],
47 | methods: {
48 | checkClientTrusted: function (chain, authType) { },
49 | checkServerTrusted: function (chain, authType) { },
50 | getAcceptedIssuers: function () { return []; }
51 | }
52 | });
53 |
54 | // Prepare the TrustManager array to pass to SSLContext.init()
55 | const TrustManagers = [TrustManager.$new()];
56 |
57 | // Get a handle on the init() on the SSLContext class
58 | const SSLContext_init = SSLContext.init.overload(
59 | '[Ljavax.net.ssl.KeyManager;', '[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom'
60 | );
61 |
62 | // Override the init method, specifying the custom TrustManager
63 | SSLContext_init.implementation = function (keyManager, trustManager, secureRandom) {
64 | //console.log(' --> Bypassing Trustmanager (Android < 7) request');
65 | SSLContext_init.call(this, keyManager, TrustManagers, secureRandom);
66 | };
67 | //console.log('[+] SSLContext');
68 | } catch (err) {
69 | //console.log('[ ] SSLContext');
70 | }
71 |
72 | // TrustManagerImpl (Android > 7)
73 | try {
74 | const array_list = Java.use("java.util.ArrayList");
75 | const TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
76 |
77 | // This step is notably what defeats the most common case: network security config
78 | TrustManagerImpl.checkTrustedRecursive.implementation = function(a1, a2, a3, a4, a5, a6) {
79 | //console.log(' --> Bypassing TrustManagerImpl checkTrusted ');
80 | return array_list.$new();
81 | }
82 |
83 | TrustManagerImpl.verifyChain.implementation = function (untrustedChain, trustAnchorChain, host, clientAuth, ocspData, tlsSctData) {
84 | //console.log(' --> Bypassing TrustManagerImpl verifyChain: ' + host);
85 | return untrustedChain;
86 | };
87 | //console.log('[+] TrustManagerImpl');
88 | } catch (err) {
89 | //console.log('[ ] TrustManagerImpl');
90 | }
91 |
92 | // OkHTTPv3 (quadruple bypass)
93 | try {
94 | // Bypass OkHTTPv3 {1}
95 | const okhttp3_Activity_1 = Java.use('okhttp3.CertificatePinner');
96 | okhttp3_Activity_1.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
97 | //console.log(' --> Bypassing OkHTTPv3 (list): ' + a);
98 | return;
99 | };
100 | //console.log('[+] OkHTTPv3 (list)');
101 | } catch (err) {
102 | //console.log('[ ] OkHTTPv3 (list)');
103 | }
104 | try {
105 | // Bypass OkHTTPv3 {2}
106 | // This method of CertificatePinner.check could be found in some old Android app
107 | const okhttp3_Activity_2 = Java.use('okhttp3.CertificatePinner');
108 | okhttp3_Activity_2.check.overload('java.lang.String', 'java.security.cert.Certificate').implementation = function (a, b) {
109 | //console.log(' --> Bypassing OkHTTPv3 (cert): ' + a);
110 | return;
111 | };
112 | //console.log('[+] OkHTTPv3 (cert)');
113 | } catch (err) {
114 | //console.log('[ ] OkHTTPv3 (cert)');
115 | }
116 | try {
117 | // Bypass OkHTTPv3 {3}
118 | const okhttp3_Activity_3 = Java.use('okhttp3.CertificatePinner');
119 | okhttp3_Activity_3.check.overload('java.lang.String', '[Ljava.security.cert.Certificate;').implementation = function (a, b) {
120 | //console.log(' --> Bypassing OkHTTPv3 (cert array): ' + a);
121 | return;
122 | };
123 | //console.log('[+] OkHTTPv3 (cert array)');
124 | } catch (err) {
125 | //console.log('[ ] OkHTTPv3 (cert array)');
126 | }
127 | try {
128 | // Bypass OkHTTPv3 {4}
129 | const okhttp3_Activity_4 = Java.use('okhttp3.CertificatePinner');
130 | okhttp3_Activity_4['check$okhttp'].implementation = function (a, b) {
131 | //console.log(' --> Bypassing OkHTTPv3 ($okhttp): ' + a);
132 | return;
133 | };
134 | //console.log('[+] OkHTTPv3 ($okhttp)');
135 | } catch (err) {
136 | //console.log('[ ] OkHTTPv3 ($okhttp)');
137 | }
138 |
139 | // Trustkit (triple bypass)
140 | try {
141 | // Bypass Trustkit {1}
142 | const trustkit_Activity_1 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
143 | trustkit_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
144 | //console.log(' --> Bypassing Trustkit OkHostnameVerifier(SSLSession): ' + a);
145 | return true;
146 | };
147 | //console.log('[+] Trustkit OkHostnameVerifier(SSLSession)');
148 | } catch (err) {
149 | //console.log('[ ] Trustkit OkHostnameVerifier(SSLSession)');
150 | }
151 | try {
152 | // Bypass Trustkit {2}
153 | const trustkit_Activity_2 = Java.use('com.datatheorem.android.trustkit.pinning.OkHostnameVerifier');
154 | trustkit_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
155 | //console.log(' --> Bypassing Trustkit OkHostnameVerifier(cert): ' + a);
156 | return true;
157 | };
158 | //console.log('[+] Trustkit OkHostnameVerifier(cert)');
159 | } catch (err) {
160 | //console.log('[ ] Trustkit OkHostnameVerifier(cert)');
161 | }
162 | try {
163 | // Bypass Trustkit {3}
164 | const trustkit_PinningTrustManager = Java.use('com.datatheorem.android.trustkit.pinning.PinningTrustManager');
165 | trustkit_PinningTrustManager.checkServerTrusted.implementation = function () {
166 | //console.log(' --> Bypassing Trustkit PinningTrustManager');
167 | };
168 | //console.log('[+] Trustkit PinningTrustManager');
169 | } catch (err) {
170 | //console.log('[ ] Trustkit PinningTrustManager');
171 | }
172 |
173 | // Appcelerator Titanium
174 | try {
175 | const appcelerator_PinningTrustManager = Java.use('appcelerator.https.PinningTrustManager');
176 | appcelerator_PinningTrustManager.checkServerTrusted.implementation = function () {
177 | //console.log(' --> Bypassing Appcelerator PinningTrustManager');
178 | };
179 | //console.log('[+] Appcelerator PinningTrustManager');
180 | } catch (err) {
181 | //console.log('[ ] Appcelerator PinningTrustManager');
182 | }
183 |
184 | // OpenSSLSocketImpl Conscrypt
185 | try {
186 | const OpenSSLSocketImpl = Java.use('com.android.org.conscrypt.OpenSSLSocketImpl');
187 | OpenSSLSocketImpl.verifyCertificateChain.implementation = function (certRefs, JavaObject, authMethod) {
188 | //console.log(' --> Bypassing OpenSSLSocketImpl Conscrypt');
189 | };
190 | //console.log('[+] OpenSSLSocketImpl Conscrypt');
191 | } catch (err) {
192 | //console.log('[ ] OpenSSLSocketImpl Conscrypt');
193 | }
194 |
195 | // OpenSSLEngineSocketImpl Conscrypt
196 | try {
197 | const OpenSSLEngineSocketImpl_Activity = Java.use('com.android.org.conscrypt.OpenSSLEngineSocketImpl');
198 | OpenSSLEngineSocketImpl_Activity.verifyCertificateChain.overload('[Ljava.lang.Long;', 'java.lang.String').implementation = function (a, b) {
199 | //console.log(' --> Bypassing OpenSSLEngineSocketImpl Conscrypt: ' + b);
200 | };
201 | //console.log('[+] OpenSSLEngineSocketImpl Conscrypt');
202 | } catch (err) {
203 | //console.log('[ ] OpenSSLEngineSocketImpl Conscrypt');
204 | }
205 |
206 | // OpenSSLSocketImpl Apache Harmony
207 | try {
208 | const OpenSSLSocketImpl_Harmony = Java.use('org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl');
209 | OpenSSLSocketImpl_Harmony.verifyCertificateChain.implementation = function (asn1DerEncodedCertificateChain, authMethod) {
210 | //console.log(' --> Bypassing OpenSSLSocketImpl Apache Harmony');
211 | };
212 | //console.log('[+] OpenSSLSocketImpl Apache Harmony');
213 | } catch (err) {
214 | //console.log('[ ] OpenSSLSocketImpl Apache Harmony');
215 | }
216 |
217 | // PhoneGap sslCertificateChecker (https://github.com/EddyVerbruggen/SSLCertificateChecker-PhoneGap-Plugin)
218 | try {
219 | const phonegap_Activity = Java.use('nl.xservices.plugins.sslCertificateChecker');
220 | phonegap_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {
221 | //console.log(' --> Bypassing PhoneGap sslCertificateChecker: ' + a);
222 | return true;
223 | };
224 | //console.log('[+] PhoneGap sslCertificateChecker');
225 | } catch (err) {
226 | //console.log('[ ] PhoneGap sslCertificateChecker');
227 | }
228 |
229 | // IBM MobileFirst pinTrustedCertificatePublicKey (double bypass)
230 | try {
231 | // Bypass IBM MobileFirst {1}
232 | const WLClient_Activity_1 = Java.use('com.worklight.wlclient.api.WLClient');
233 | WLClient_Activity_1.getInstance().pinTrustedCertificatePublicKey.overload('java.lang.String').implementation = function (cert) {
234 | //console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string): ' + cert);
235 | return;
236 | };
237 | //console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string)');
238 | } catch (err) {
239 | //console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string)');
240 | }
241 | try {
242 | // Bypass IBM MobileFirst {2}
243 | const WLClient_Activity_2 = Java.use('com.worklight.wlclient.api.WLClient');
244 | WLClient_Activity_2.getInstance().pinTrustedCertificatePublicKey.overload('[Ljava.lang.String;').implementation = function (cert) {
245 | //console.log(' --> Bypassing IBM MobileFirst pinTrustedCertificatePublicKey (string array): ' + cert);
246 | return;
247 | };
248 | //console.log('[+] IBM MobileFirst pinTrustedCertificatePublicKey (string array)');
249 | } catch (err) {
250 | //console.log('[ ] IBM MobileFirst pinTrustedCertificatePublicKey (string array)');
251 | }
252 |
253 | // IBM WorkLight (ancestor of MobileFirst) HostNameVerifierWithCertificatePinning (quadruple bypass)
254 | try {
255 | // Bypass IBM WorkLight {1}
256 | const worklight_Activity_1 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
257 | worklight_Activity_1.verify.overload('java.lang.String', 'javax.net.ssl.SSLSocket').implementation = function (a, b) {
258 | //console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket): ' + a);
259 | return;
260 | };
261 | //console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)');
262 | } catch (err) {
263 | //console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSocket)');
264 | }
265 | try {
266 | // Bypass IBM WorkLight {2}
267 | const worklight_Activity_2 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
268 | worklight_Activity_2.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
269 | //console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (cert): ' + a);
270 | return;
271 | };
272 | //console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)');
273 | } catch (err) {
274 | //console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (cert)');
275 | }
276 | try {
277 | // Bypass IBM WorkLight {3}
278 | const worklight_Activity_3 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
279 | worklight_Activity_3.verify.overload('java.lang.String', '[Ljava.lang.String;', '[Ljava.lang.String;').implementation = function (a, b) {
280 | //console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (string string): ' + a);
281 | return;
282 | };
283 | //console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)');
284 | } catch (err) {
285 | //console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (string string)');
286 | }
287 | try {
288 | // Bypass IBM WorkLight {4}
289 | const worklight_Activity_4 = Java.use('com.worklight.wlclient.certificatepinning.HostNameVerifierWithCertificatePinning');
290 | worklight_Activity_4.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
291 | //console.log(' --> Bypassing IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession): ' + a);
292 | return true;
293 | };
294 | //console.log('[+] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)');
295 | } catch (err) {
296 | //console.log('[ ] IBM WorkLight HostNameVerifierWithCertificatePinning (SSLSession)');
297 | }
298 |
299 | // Conscrypt CertPinManager
300 | try {
301 | const conscrypt_CertPinManager_Activity = Java.use('com.android.org.conscrypt.CertPinManager');
302 | conscrypt_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
303 | //console.log(' --> Bypassing Conscrypt CertPinManager: ' + a);
304 | return true;
305 | };
306 | //console.log('[+] Conscrypt CertPinManager');
307 | } catch (err) {
308 | //console.log('[ ] Conscrypt CertPinManager');
309 | }
310 |
311 | // CWAC-Netsecurity (unofficial back-port pinner for Android<4.2) CertPinManager
312 | try {
313 | const cwac_CertPinManager_Activity = Java.use('com.commonsware.cwac.netsecurity.conscrypt.CertPinManager');
314 | cwac_CertPinManager_Activity.isChainValid.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
315 | //console.log(' --> Bypassing CWAC-Netsecurity CertPinManager: ' + a);
316 | return true;
317 | };
318 | //console.log('[+] CWAC-Netsecurity CertPinManager');
319 | } catch (err) {
320 | //console.log('[ ] CWAC-Netsecurity CertPinManager');
321 | }
322 |
323 | // Worklight Androidgap WLCertificatePinningPlugin
324 | try {
325 | const androidgap_WLCertificatePinningPlugin_Activity = Java.use('com.worklight.androidgap.plugin.WLCertificatePinningPlugin');
326 | androidgap_WLCertificatePinningPlugin_Activity.execute.overload('java.lang.String', 'org.json.JSONArray', 'org.apache.cordova.CallbackContext').implementation = function (a, b, c) {
327 | //console.log(' --> Bypassing Worklight Androidgap WLCertificatePinningPlugin: ' + a);
328 | return true;
329 | };
330 | //console.log('[+] Worklight Androidgap WLCertificatePinningPlugin');
331 | } catch (err) {
332 | //console.log('[ ] Worklight Androidgap WLCertificatePinningPlugin');
333 | }
334 |
335 | // Netty FingerprintTrustManagerFactory
336 | try {
337 | const netty_FingerprintTrustManagerFactory = Java.use('io.netty.handler.ssl.util.FingerprintTrustManagerFactory');
338 | netty_FingerprintTrustManagerFactory.checkTrusted.implementation = function (type, chain) {
339 | //console.log(' --> Bypassing Netty FingerprintTrustManagerFactory');
340 | };
341 | //console.log('[+] Netty FingerprintTrustManagerFactory');
342 | } catch (err) {
343 | //console.log('[ ] Netty FingerprintTrustManagerFactory');
344 | }
345 |
346 | // Squareup CertificatePinner [OkHTTP Bypassing Squareup CertificatePinner (cert): ' + a);
352 | return;
353 | };
354 | //console.log('[+] Squareup CertificatePinner (cert)');
355 | } catch (err) {
356 | //console.log('[ ] Squareup CertificatePinner (cert)');
357 | }
358 | try {
359 | // Bypass Squareup CertificatePinner {2}
360 | const Squareup_CertificatePinner_Activity_2 = Java.use('com.squareup.okhttp.CertificatePinner');
361 | Squareup_CertificatePinner_Activity_2.check.overload('java.lang.String', 'java.util.List').implementation = function (a, b) {
362 | //console.log(' --> Bypassing Squareup CertificatePinner (list): ' + a);
363 | return;
364 | };
365 | //console.log('[+] Squareup CertificatePinner (list)');
366 | } catch (err) {
367 | //console.log('[ ] Squareup CertificatePinner (list)');
368 | }
369 |
370 | // Squareup OkHostnameVerifier [OkHTTP v3] (double bypass)
371 | try {
372 | // Bypass Squareup OkHostnameVerifier {1}
373 | const Squareup_OkHostnameVerifier_Activity_1 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
374 | Squareup_OkHostnameVerifier_Activity_1.verify.overload('java.lang.String', 'java.security.cert.X509Certificate').implementation = function (a, b) {
375 | //console.log(' --> Bypassing Squareup OkHostnameVerifier (cert): ' + a);
376 | return true;
377 | };
378 | //console.log('[+] Squareup OkHostnameVerifier (cert)');
379 | } catch (err) {
380 | //console.log('[ ] Squareup OkHostnameVerifier (cert)');
381 | }
382 | try {
383 | // Bypass Squareup OkHostnameVerifier {2}
384 | const Squareup_OkHostnameVerifier_Activity_2 = Java.use('com.squareup.okhttp.internal.tls.OkHostnameVerifier');
385 | Squareup_OkHostnameVerifier_Activity_2.verify.overload('java.lang.String', 'javax.net.ssl.SSLSession').implementation = function (a, b) {
386 | //console.log(' --> Bypassing Squareup OkHostnameVerifier (SSLSession): ' + a);
387 | return true;
388 | };
389 | //console.log('[+] Squareup OkHostnameVerifier (SSLSession)');
390 | } catch (err) {
391 | //console.log('[ ] Squareup OkHostnameVerifier (SSLSession)');
392 | }
393 |
394 | // Android WebViewClient (double bypass)
395 | try {
396 | // Bypass WebViewClient {1} (deprecated from Android 6)
397 | const AndroidWebViewClient_Activity_1 = Java.use('android.webkit.WebViewClient');
398 | AndroidWebViewClient_Activity_1.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
399 | //console.log(' --> Bypassing Android WebViewClient (SslErrorHandler)');
400 | };
401 | //console.log('[+] Android WebViewClient (SslErrorHandler)');
402 | } catch (err) {
403 | //console.log('[ ] Android WebViewClient (SslErrorHandler)');
404 | }
405 | try {
406 | // Bypass WebViewClient {2}
407 | const AndroidWebViewClient_Activity_2 = Java.use('android.webkit.WebViewClient');
408 | AndroidWebViewClient_Activity_2.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.WebResourceRequest', 'android.webkit.WebResourceError').implementation = function (obj1, obj2, obj3) {
409 | //console.log(' --> Bypassing Android WebViewClient (WebResourceError)');
410 | };
411 | //console.log('[+] Android WebViewClient (WebResourceError)');
412 | } catch (err) {
413 | //console.log('[ ] Android WebViewClient (WebResourceError)');
414 | }
415 |
416 | // Apache Cordova WebViewClient
417 | try {
418 | const CordovaWebViewClient_Activity = Java.use('org.apache.cordova.CordovaWebViewClient');
419 | CordovaWebViewClient_Activity.onReceivedSslError.overload('android.webkit.WebView', 'android.webkit.SslErrorHandler', 'android.net.http.SslError').implementation = function (obj1, obj2, obj3) {
420 | //console.log(' --> Bypassing Apache Cordova WebViewClient');
421 | obj3.proceed();
422 | };
423 | } catch (err) {
424 | //console.log('[ ] Apache Cordova WebViewClient');
425 | }
426 |
427 | // Boye AbstractVerifier
428 | try {
429 | const boye_AbstractVerifier = Java.use('ch.boye.httpclientandroidlib.conn.ssl.AbstractVerifier');
430 | boye_AbstractVerifier.verify.implementation = function (host, ssl) {
431 | //console.log(' --> Bypassing Boye AbstractVerifier: ' + host);
432 | };
433 | } catch (err) {
434 | //console.log('[ ] Boye AbstractVerifier');
435 | }
436 | });
437 |
438 | //console.log("Unpinning setup cmopleted");
439 | //console.log("---");
440 |
441 | }, 0);
--------------------------------------------------------------------------------
/interactor.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import hashlib
3 | import itertools
4 | import json
5 | import logging
6 | import os
7 | import random
8 | import sqlite3
9 | import sys
10 | import time
11 | from functools import partial
12 |
13 | import translators
14 |
15 | import timeout
16 |
17 | # pm list packages -3 | cut -d':' -f2 | tr '\r' ' ' | grep -v com.github.shadowsocks
18 | # 1- adb reboot recovery
19 | # 2- twrp wipe system ; twrp wipe dalvik ; twrp wipe data ; twrp wipe cache ; rm -rf /sdcard/*
20 | # 3- adb push TWRP /sdcard/
21 | # 4- twrp restore clean
22 | # 5- rm -rf /sdcard/TWRP
23 | # adb shell dumpsys window | grep com.android.vending
24 | # adb shell dumpsys activity activities | grep mResumedActivity
25 |
26 | # pm list packages -3 | cut -c9- | grep -Ev "(com.github.shadowsocks|org.proxydroid|com.fakemygps.android|org.meowcat.edxposed.manager|edu.berkeley.icsi.haystack|com.topjohnwu.magisk|app.greyshirts.sslcapture|tw.fatminmin.xposed.minminguard|com.cofface.ivader)" | xargs pm uninstall
27 |
28 |
29 | def dictionary(text):
30 | en = text
31 | if len(text) > 2:
32 | con = sqlite3.connect('dict.db')
33 | cur = con.cursor()
34 | cur.execute(
35 | '''CREATE TABLE IF NOT EXISTS words (ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, original text, en text)''')
36 | cur.execute("select en from words where original = ?", (text,))
37 | row = cur.fetchone()
38 |
39 | if row == None:
40 | i = 0
41 | while i < 10:
42 | # print("zzz")
43 | # print(i)
44 | try:
45 | with timeout.timeout(seconds=10):
46 | en = translators.google(text)
47 | break
48 | except:
49 | i += 1
50 | time.sleep(2)
51 | continue
52 | logging.debug("dict")
53 | cur.execute("insert into words values (?,?,?)",
54 | (None, text, en))
55 | con.commit()
56 | else:
57 | en = row[0]
58 | con.close()
59 | return en
60 |
61 |
62 | def find_clickable_enable(view, text="", click=False, translate=True, exclude=["None"], obj_class=["android.widget.checkedtextview", "android.view.view", "android.widget.button", "android.widget.textview","android.widget.LinearLayout"], attr="text"):
63 | if (view.isClickable() or view.__getattr__('isEnabled')() or view.__getattr__('checkable')()) and view.getClass().lower() in obj_class:
64 | if attr.lower() == "text":
65 | # obj_text = (view.getText()).lower()
66 | obj_text = dictionary(view.getText()).lower(
67 | ) if translate else view.getText().lower()
68 | elif attr.lower() == "id":
69 | obj_text = view.getId().lower()
70 | if "/" in obj_text:
71 | obj_text = obj_text.split("/")[1]
72 | elif attr.lower() in ("cd","content-desc"):
73 | # obj_text = (view.getContentDescription()).lower()
74 | obj_text = dictionary(view.getContentDescription()).lower(
75 | ) if translate else view.getContentDescription().lower()
76 | else:
77 | return None
78 | text = text.lower()
79 | if (text == obj_text and exclude == ['None']) or (text in obj_text and len(obj_text) < 64 and (not any(substring in obj_text for substring in exclude) and exclude != ['None'])):
80 | if click:
81 | logging.debug("::"+text)
82 | view.touch()
83 | return True
84 |
85 |
86 | def window_hash(root):
87 | id_list = [v.getId()
88 | for v in finder(root, lambda v: True if v.getId() else False)]
89 | id_list.sort()
90 | return hashlib.sha256(json.dumps(id_list).encode('utf-8')).hexdigest()
91 |
92 |
93 | def problem(view):
94 | if view.getText().startswith("Can't download"):
95 | # "You're offline"
96 | return True
97 |
98 |
99 | def finder(root, transform=str, nlist=None, count=[-1], window_hash="", memory=None):
100 | if memory is None:
101 | memory = dict()
102 | if nlist is None:
103 | nlist = []
104 | if not root or count[0] == 0 or (memory.get(window_hash) != None and (root.getUniqueId()+root.getId()+str(root.isClickable())+str(root.__getattr__('isEnabled')())) in memory.get(window_hash)):
105 | return
106 | if transform(root) and (window_hash == "" or memory.get(window_hash) == None or (root.getUniqueId()+root.getId()+str(root.isClickable())+str(root.__getattr__('isEnabled')())) not in memory.get(window_hash)):
107 | if count[0] != -1:
108 | count[0] -= 1
109 | nlist.append(root)
110 | if window_hash != "":
111 | if window_hash in memory:
112 | memory.get(window_hash).add(root.getUniqueId(
113 | )+root.getId()+str(root.isClickable())+str(root.__getattr__('isEnabled')()))
114 | # memory.update(
115 | # {window_hash: {root.getUniqueId()+root.getId()}})
116 | else:
117 | memory.update(
118 | {window_hash: {root.getUniqueId()+root.getId()+str(root.isClickable())+str(root.__getattr__('isEnabled')())}})
119 |
120 | for ch in root.children:
121 | finder(ch, transform=transform, nlist=nlist, count=count,
122 | window_hash=window_hash, memory=memory)
123 | return nlist
124 |
125 |
126 | def get_root(device, window=-1, sleep=0.5):
127 | for chanse in range(0, 10):
128 | try:
129 | for n in device.vc.dump(window=window, sleep=sleep):
130 | if n.getParent() == None:
131 | return n
132 | except Exception as e:
133 | if chanse < 3:
134 | time.sleep(2)
135 | continue
136 | raise e
137 |
138 |
139 | class GooglePlay():
140 | def __init__(self, device):
141 | self.device = device
142 |
143 | def install(self, package):
144 | self.device.close_app("com.android.vending")
145 | self.device.wait_if_internet_isnt_available()
146 | self.open_package_page(package)
147 | # time.sleep(3)
148 | name = self.get_package_name()
149 | root = get_root(self.device)
150 | if None in (self.is_package_installable(package), self.get_package_name()) and finder(root, transform=partial(
151 | find_clickable_enable, text="Understood", click=True, translate=False)) == []:
152 | logging.debug(str(name) + " " + package)
153 | return None
154 | try:
155 | with timeout.timeout(seconds=200):
156 | uninstallable = 0
157 | while True:
158 | if os.path.exists("./skip"):
159 | os.remove("./skip")
160 | return None
161 | # self.device.close_app("com.android.chrome")
162 | # self.device.close_app("org.lineageos.jelly")
163 | logging.debug("4444")
164 | self.device.wait_if_internet_isnt_available()
165 | self.device.d.wake()
166 | # time.sleep(2)
167 | root = get_root(self.device)
168 | if self.is_gp_open(root=root) == False or name != self.get_package_name():
169 | self.open_package_page(package)
170 |
171 | if finder(root, transform=partial(
172 | find_clickable_enable, text="Open", translate=False)) or finder(root, transform=partial(
173 | find_clickable_enable, text="Enable", translate=False)):
174 | return True
175 |
176 | if finder(root, transform=partial(
177 | find_clickable_enable, text="Play", translate=False)):
178 | return True
179 |
180 | if finder(root, transform=partial(
181 | find_clickable_enable, text="Uninstall", translate=False)):
182 | if uninstallable >= 2:
183 | return None
184 | uninstallable += 1
185 | continue
186 |
187 | if finder(root, transform=partial(
188 | find_clickable_enable, text="Install", click=True, translate=False)) or finder(root, transform=partial(
189 | find_clickable_enable, text="Try again", click=True, translate=False)) or finder(root, transform=partial(
190 | find_clickable_enable, text="Retry", click=True, translate=False)) or finder(root, transform=partial(
191 | find_clickable_enable, text="Accept", click=True, translate=False)) or finder(root, transform=partial(
192 | find_clickable_enable, text="Update", click=True, translate=False)) or finder(root, transform=partial(
193 | find_clickable_enable, text="Skip", click=True, translate=False)) or finder(root, transform=partial(
194 | find_clickable_enable, text="Accept", click=True, translate=False)) or finder(root, transform=partial(
195 | find_clickable_enable, text="No thanks", click=True, translate=False)) or finder(root, transform=partial(
196 | find_clickable_enable, text="Continue", click=True, translate=False)) or finder(root, transform=partial(
197 | find_clickable_enable, text="Ok", click=True, translate=False)):
198 | logging.debug("5555")
199 | continue
200 | if finder(root, transform=partial(
201 | find_clickable_enable, text="Got it", click=True, translate=False)) or finder(root, transform=partial(
202 | find_clickable_enable, text="Understood", click=True, translate=False)):
203 | return None
204 | except:
205 | # return None
206 | self.device.d.wake()
207 | root = get_root(self.device)
208 | if self.is_gp_open(root=root) == False or name != self.get_package_name():
209 | self.open_package_page(package)
210 | if finder(root, transform=partial(find_clickable_enable, text="Cancel", click=True, translate=False)) or finder(root, transform=partial(find_clickable_enable, text="Uninstall", click=True, translate=False)):
211 | return None
212 | else:
213 | time.sleep(2)
214 | self.device.uninstall_app(package)
215 | return None
216 |
217 | def is_package_installable(self, package):
218 | if self.is_gp_open():
219 | items = [c.getText() for i in self.device.vc.dump() if i.getClass() == "android.view.ViewGroup" and i.getParent(
220 | ).getClass() != "android.widget.LinearLayout" for c in i.getChildren()]
221 | if "Install" in items or "Update" in items or "Open" in items:
222 | return True
223 |
224 | def is_package_installed(self, package, name):
225 | if self.is_gp_open() or name == self.get_package_name():
226 | if self.device.uiautomator(
227 | text="Open",
228 | className="android.widget.Button",
229 | clickable="true",
230 | enabled="true",
231 | ).exists:
232 | return True
233 | return False
234 |
235 | def is_gp_open(self, root='root'):
236 | if root == 'root':
237 | root = get_root(self.device)
238 | # google loading page hash
239 | while window_hash(root) == "bcdec05b796550fb1c36544f80af3d15dec9c4d4bcede57fe9187ab65ce632be":
240 | root = get_root(self.device)
241 | if self.device.get_current_activity() and self.device.get_current_activity().startswith("com.android.vending") and (not finder(root, transform=problem)):
242 | return True
243 | return False
244 |
245 | def get_package_name(self):
246 | if self.is_gp_open():
247 | _try = 0
248 | while _try < 2:
249 | while True:
250 | root = get_root(self.device)
251 | if (finder(root, transform=partial(
252 | find_clickable_enable, text="Retry", click=True, translate=False)) or finder(root, transform=partial(
253 | find_clickable_enable, text="Understood", click=True, translate=False)) or finder(root, transform=partial(
254 | find_clickable_enable, text="Skip", click=True, translate=False)) or finder(root, transform=partial(
255 | find_clickable_enable, text="Accept", click=True, translate=False)) or finder(root, transform=partial(
256 | find_clickable_enable, text="No, thanks", click=True, translate=False)) or finder(root, transform=partial(
257 | find_clickable_enable, text="Continue", click=True, translate=False)) or finder(root, transform=partial(
258 | find_clickable_enable, text="Got it", click=True, translate=False))) == []:
259 | logging.debug("7777")
260 | break
261 | try:
262 | return [i.getText() for i in self.device.vc.dump() if i.getClass() == "android.widget.TextView" and i.getParent().getClass() == "android.widget.LinearLayout"][0]
263 | except:
264 | _try += 1
265 | self.device.d.shell('input keyevent KEYCODE_BACK')
266 | # if not re.match(r'^(2[0-3]|[01]?[0-9]):([0-5]?[0-9])$', name):
267 |
268 | def open_package_page(self, package):
269 | self.device.d.wake()
270 | self.device.shell(
271 | "am start -a android.intent.action.VIEW -d 'market://details?id=" + package + "'")
272 | for _ in range(0, 5):
273 | time.sleep(0.5)
274 | if self.is_gp_open() == True:
275 | return True
276 | return False
277 |
278 |
279 | # def remove_space(words):
280 | # nd = dict()
281 | # for key, value in words.items():
282 | # if ' ' in key:
283 | # nd[key.replace(' ', '')] = list(w.replace(' ', '')
284 | # if ' ' in w else w for w in value)
285 | # nd[key.replace(' ', '-')] = list(w.replace(' ', '-')
286 | # if ' ' in w else w for w in value)
287 | # nd[key.replace(' ', '_')] = list(w.replace(' ', '_')
288 | # if ' ' in w else w for w in value)
289 | # else:
290 | # nd[key] = list(itertools.chain.from_iterable([w.replace(' ', ''), w.replace(
291 | # ' ', '_'), w.replace(' ', '-')] if ' ' in w else [w] for w in value))
292 | # return nd
293 |
294 |
295 | class App:
296 | def __init__(self, device, package, stage, analysis_time, param_path="./interactor_parameters.json"):
297 | self.d = device
298 | self.p = package
299 | self.t = analysis_time
300 | self.stage = str(stage)
301 | self.memory = dict()
302 | with open(param_path, 'r') as file:
303 | self.params = json.loads(file.read())
304 |
305 | def get_params(self, text=True):
306 | if text:
307 | return self.params
308 | else:
309 | res = dict()
310 | for cat, val in self.params.items():
311 | nd = dict()
312 | for key, value in val.items():
313 |
314 | if ' ' in key:
315 | nd[key.replace(' ', '')] = value if type(value) is not list else list(w.replace(' ', '')
316 | if ' ' in w else w for w in value)
317 | nd[key.replace(' ', '-')] = value if type(value) is not list else list(w.replace(' ', '-')
318 | if ' ' in w else w for w in value)
319 | nd[key.replace(' ', '_')] = value if type(value) is not list else list(w.replace(' ', '_')
320 | if ' ' in w else w for w in value)
321 | else:
322 | nd[key] = value if type(value) is not list else list(itertools.chain.from_iterable([w.replace(' ', ''), w.replace(
323 | ' ', '_'), w.replace(' ', '-')] if ' ' in w else [w] for w in value))
324 | res[cat] = nd
325 | return res
326 |
327 | def find_and_click_by_text(self, root, obj_class):
328 | w_hash = window_hash(root)
329 | # print("----------")
330 | current_activity = self.d.get_current_activity()
331 | if current_activity in ["com.google.android.gms/.signin.activity.ConsentActivity", "com.google.android.gms/.auth.uiflows.consent.BrowserConsentActivity"]:
332 | if len(finder(root, transform=partial(find_clickable_enable, text="allow", click=True)) + finder(root, transform=partial(find_clickable_enable, text="continue", click=True))) == 0:
333 | w = self.d.d.display['width']
334 | h = self.d.d.display['height']
335 | s = (w / 2, (h / 3) * 2)
336 | e = (w / 2, (h / 3))
337 | self.d.d.drag(s, e, 500, 20, -1)
338 | self.d.d.drag(s, e, 500, 20, -1)
339 | # google found
340 | return True
341 | # time.sleep(1)
342 | elif current_activity in ["com.android.vending/com.google.android.finsky.activities.MarketDeepLinkHandlerActivity", "com.android.vending/com.google.android.finsky.billing.acquire.LockToPortraitUiBuilderHostActivity", "com.android.vending/com.google.android.finsky.billing.acquire.SheetUiBuilderHostActivity"] or current_activity.endswith("/com.google.android.gms.ads.AdActivity") or current_activity.endswith("/com.unity3d.services.ads.adunit.AdUnitActivity") or current_activity.endswith("/com.unity3d.ads.adunit.AdUnitActivity"):
343 | time.sleep(1.5)
344 | # com.android.vending/com.google.android.finsky.billing.acquire.SheetUiBuilderHostActivity
345 | print("////////////////")
346 | self.d.shell('input keyevent KEYCODE_BACK')
347 | return True
348 | for include, exclude in self.get_params()["keywords"].items():
349 | for node in finder(root, transform=partial(
350 | find_clickable_enable, text=include, exclude=exclude, obj_class=obj_class, attr="CD"), count=[1], window_hash=w_hash, memory=self.memory):
351 | logging.debug("id12:"+include)
352 | node.touch()
353 | return True
354 | for include, exclude in self.get_params(text=False)["keywords"].items():
355 | for node in finder(root, transform=partial(
356 | find_clickable_enable, text=include, exclude=exclude, obj_class=obj_class, attr="Id"), count=[1], window_hash=w_hash, memory=self.memory):
357 | logging.debug("id13:"+include)
358 | node.touch()
359 | return True
360 | for include, exclude in self.get_params()["keywords"].items():
361 | for node in finder(root, transform=partial(
362 | find_clickable_enable, text=include, exclude=exclude, obj_class=obj_class), count=[1], window_hash=w_hash, memory=self.memory):
363 | node.touch()
364 | time.sleep(0.5)
365 | return True
366 | # print("----------1-2")
367 | # for include, exclude in self.get_params()["avoid"].items():
368 | # for node in finder(root, transform=partial(
369 | # find_clickable_enable, text=include, exclude=exclude, obj_class=obj_class), count=[1], window_hash=w_hash, memory=self.memory):
370 | # # com.android.vending/com.google.android.finsky.activities.MarketDeepLinkHandlerActivity install
371 | # # */com.google.android.gms.ads.AdActivity
372 | # # com.android.vending/com.google.android.finsky.billing.acquire.LockToPortraitUiBuilderHostActivity
373 | # logging.debug("id-----------------------------:"+node.getText())
374 | # logging.debug("id11:"+include)
375 | # print("--+++++++++++--"+self.d.get_current_activity())
376 | # node.touch()
377 | # return True
378 | time.sleep(1)
379 | return False
380 |
381 | def find_and_scroll(self, root):
382 | pass
383 |
384 | def find_input_and_fill(self, root, obj_class):
385 | w_hash = window_hash(root)
386 | for key, value in self.get_params()["input"].items():
387 | for node in finder(root, transform=partial(
388 | find_clickable_enable, text=key, exclude=[], obj_class=obj_class), count=[1], window_hash=w_hash, memory=self.memory):
389 | logging.debug("id1:"+node.getId())
390 | node.setText(value)
391 | return True
392 | for key, value in self.get_params(text=False)["input"].items():
393 | for node in finder(root, transform=partial(
394 | find_clickable_enable, text=key, exclude=[], obj_class=obj_class, attr="Id"), count=[1], window_hash=w_hash, memory=self.memory):
395 | logging.debug("id2:"+node.getId())
396 | logging.debug("v1:"+value)
397 | node.setText(value)
398 | return True
399 | # for node in finder(root, transform=partial(
400 | # find_clickable_enable, text=key, obj_class=obj_class), count=[1], window_hash=w_hash, memory=self.memory):
401 | # node.setText(value)
402 | # return True
403 | return False
404 |
405 | def scroll_down(self, w, h):
406 | w = self.d.d.display['width']
407 | h = self.d.d.display['height']
408 | self.d.shell("input swipe {} {} {} {} 100".format(
409 | w / 2, (h / 3) * 2, w / 2, h / 3))
410 |
411 | def scroll_up(self, w, h):
412 | w = self.d.d.display['width']
413 | h = self.d.d.display['height']
414 | self.d.shell("input swipe {} {} {} {} 100".format(
415 | w / 2, h / 3, w / 2, (h / 3) * 2))
416 |
417 | def scroll_right(self, w, h):
418 | self.d.shell("input swipe {} {} {} {} 100".format(
419 | w / 5, h / 2, (w / 5 * 4), h / 2, 500, 20))
420 |
421 | def dumb_interaction(self, deep=False):
422 | click_command = ""
423 | w = int(self.d.display.y)
424 | h = int(self.d.display.x - self.d.display.statusbar)
425 | if bool(random.getrandbits(1)):
426 | self.scroll_up(w, h)
427 | else:
428 | self.scroll_down(w, h)
429 | self.scroll_right(w, h)
430 | if deep:
431 | base = (10, 5)
432 | else:
433 | base = (6, 3)
434 | for y in reversed(range(int(h/base[0]), h, int(h/base[0]))):
435 | for x in range(int(w/base[1]), w, int(w/base[1])):
436 | click_command += "input tap {} {};".format(x, y)
437 | self.d.shell(click_command)
438 |
439 | def smart(self):
440 | futile = -1
441 | back_key = 2
442 | app_closed = 0
443 | time.sleep(8)
444 | start = int(time.time())
445 | for _ in range(0, 100):
446 | if os.path.exists("./skip"):
447 | os.remove("./skip")
448 | break
449 | if int(time.time()) - start > 300: # 300
450 | break
451 | if self.d.is_app_crashed(self.p):
452 | with open("out/"+self.p+"/crash-"+self.stage+"-"+str(int(time.time()))+".txt", "a") as f:
453 | f.write(self.d.shell('logcat -d *:E -t \''+datetime.datetime.fromtimestamp(
454 | self.t).strftime('%m-%d %H:%M:%S.0')+'\'|base64')+"\n")
455 | self.d.shell('input keyevent KEYCODE_BACK')
456 | if self.d.is_app_hangs(self.p):
457 | with open("out/"+self.p+"/hang-"+self.stage+"-"+str(int(time.time()))+".txt", "a") as f:
458 | f.write(str(int(time.time()))+"\n")
459 | self.d.shell('input keyevent KEYCODE_BACK')
460 |
461 | if self.d.frida.is_lost != 0:
462 | os.system('kill -9 {pid}'.format(pid=os.getpid()))
463 |
464 | self.d.d.shell(
465 | "am broadcast -n com.research.helper/.SendGPS -e lat 45.4950378 -e lon -73.5779508 -e accurate 0.5 -e alt 5")
466 |
467 | try:
468 | # print("sleep 10")
469 | # time.sleep(10)
470 |
471 | if not self.d.is_app_open(self.p):
472 | if app_closed >= 3:
473 | break
474 | app_closed += 1
475 | self.d.run_app(self.p, close=False)
476 | # print("sleep 10.1")
477 | # time.sleep(10)
478 |
479 | memory_snapshot = len(str(self.memory))
480 | self.d.wait_if_internet_isnt_available()
481 | self.d.d.wake()
482 |
483 | root = get_root(self.d)
484 | print("**---++----")
485 | for _ in range(0, 10):
486 | self.find_input_and_fill(
487 | root, obj_class=["android.widget.edittext"])
488 |
489 | for _ in range(0, 10):
490 | if finder(root, transform=partial(
491 | find_clickable_enable, text="9", obj_class=["android.widget.button"], click=True), count=[1], window_hash=window_hash(root)):
492 | root = get_root(self.d)
493 | else:
494 | break
495 | windowhash = window_hash(root)
496 |
497 | if not self.d.is_app_open(self.p):
498 | if app_closed >= 3:
499 | break
500 | app_closed += 1
501 | self.d.run_app(self.p, close=False)
502 | continue
503 |
504 | fct = self.find_and_click_by_text(
505 | root, obj_class=["android.widget.checkedtextview", "android.view.view", "android.widget.button", "android.widget.textview", "android.widget.imageview", "android.widget.imagebutton","android.widget.LinearLayout"])
506 | logging.debug("mem:"+str(self.memory))
507 | if fct == False:
508 | if windowhash == get_root(self.d):
509 | self.d.shell('input keyevent KEYCODE_BACK')
510 | if memory_snapshot == len(str(self.memory)):
511 | logging.debug("futile:"+str(futile))
512 | if futile >= 4:
513 | if back_key <= 0:
514 | break
515 | futile -= 1
516 | self.d.shell('input keyevent KEYCODE_BACK')
517 | time.sleep(1)
518 | if not self.d.is_app_open(self.p):
519 | break
520 | back_key -= 1
521 | elif futile == 3:
522 | self.dumb_interaction()
523 | futile += 1
524 | time.sleep(abs(futile)/2)
525 | logging.debug("xxxxxx")
526 | else:
527 | logging.debug("aaaaaa")
528 | back_key = 3
529 | futile = 1
530 | except ValueError as ee:
531 | logging.debug("xsxs")
532 | logging.debug(ee)
533 | self.dumb_interaction()
534 | if back_key <= 0:
535 | break
536 |
537 | self.d.shell('input keyevent KEYCODE_BACK')
538 | back_key -= 1
539 | except RuntimeError:
540 | self.dumb_interaction(deep=True)
541 | # self.d.shell('input keyevent KEYCODE_BACK')
542 | # logging.debug(self.memory)
543 | # time.sleep(20)
544 | # finder(root, transform=partial(find_button_click, text="Update"))
545 | # logging.debug(self.d.vc.dump())
546 |
547 | def find_similar_button(self):
548 | pass
549 |
550 | def dump(self):
551 | pass
552 |
--------------------------------------------------------------------------------