├── .gitignore
├── LICENSE
├── README.md
├── agent
├── build.gradle
├── lint.xml
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── WithSecure
│ │ └── dz
│ │ ├── Agent.java
│ │ ├── EndpointAdapter.java
│ │ ├── activities
│ │ ├── AboutActivity.java
│ │ ├── ConnectorActivity.java
│ │ ├── EndpointActivity.java
│ │ ├── EndpointSettingsActivity.java
│ │ ├── MainActivity.java
│ │ ├── ServerActivity.java
│ │ ├── SettingsActivity.java
│ │ └── StartBroadcastActivity.java
│ │ ├── helpers
│ │ └── IntentProxyToContentProvider.java
│ │ ├── models
│ │ ├── EndpointManager.java
│ │ └── ServerSettings.java
│ │ ├── providers
│ │ └── Provider.java
│ │ ├── receivers
│ │ ├── StartMainActivityReceiver.java
│ │ └── StartServiceReceiver.java
│ │ ├── service_connectors
│ │ ├── ClientServiceConnection.java
│ │ ├── IncomingReplyHandler.java
│ │ ├── ServerServiceConnection.java
│ │ └── SessionServiceConnection.java
│ │ ├── services
│ │ ├── ClientService.java
│ │ ├── ConnectorService.java
│ │ ├── ServerService.java
│ │ └── SessionService.java
│ │ └── views
│ │ ├── CheckListItemView.java
│ │ ├── ConnectorStatusIndicator.java
│ │ ├── EndpointListRowView.java
│ │ ├── EndpointListView.java
│ │ ├── ServerListRowView.java
│ │ └── logger
│ │ ├── LogMessageAdapter.java
│ │ └── LogMessageRowView.java
│ └── res
│ ├── drawable-hdpi
│ ├── drozer.png
│ ├── ic_action_delete.png
│ ├── ic_action_edit.png
│ ├── ic_action_new.png
│ ├── ic_action_online.png
│ ├── ic_action_refresh.png
│ ├── ic_action_search.png
│ ├── ic_action_unknown.png
│ ├── ic_input_add.png
│ ├── ic_launcher.png
│ ├── ic_notification.png
│ ├── ic_stat_active.png
│ ├── ic_stat_offline.png
│ ├── ic_stat_online.png
│ └── ic_stat_unknown.png
│ ├── drawable-ldpi
│ ├── ic_action_delete.png
│ ├── ic_action_edit.png
│ ├── ic_action_new.png
│ ├── ic_action_online.png
│ ├── ic_action_refresh.png
│ ├── ic_action_unknown.png
│ ├── ic_input_add.png
│ ├── ic_stat_active.png
│ ├── ic_stat_offline.png
│ ├── ic_stat_online.png
│ └── ic_stat_unknown.png
│ ├── drawable-mdpi
│ ├── ic_action_delete.png
│ ├── ic_action_edit.png
│ ├── ic_action_new.png
│ ├── ic_action_online.png
│ ├── ic_action_refresh.png
│ ├── ic_action_search.png
│ ├── ic_action_unknown.png
│ ├── ic_input_add.png
│ ├── ic_launcher.png
│ ├── ic_notification.png
│ ├── ic_stat_active.png
│ ├── ic_stat_offline.png
│ ├── ic_stat_online.png
│ └── ic_stat_unknown.png
│ ├── drawable-xhdpi
│ ├── ic_action_delete.png
│ ├── ic_action_edit.png
│ ├── ic_action_new.png
│ ├── ic_action_online.png
│ ├── ic_action_refresh.png
│ ├── ic_action_search.png
│ ├── ic_action_unknown.png
│ ├── ic_input_add.png
│ ├── ic_launcher.png
│ ├── ic_notification.png
│ ├── ic_stat_active.png
│ ├── ic_stat_offline.png
│ ├── ic_stat_online.png
│ └── ic_stat_unknown.png
│ ├── drawable
│ └── ic_stat_connecting.xml
│ ├── layout-land
│ └── activity_main.xml
│ ├── layout-v14
│ ├── toggle_endpoint.xml
│ └── toggle_server.xml
│ ├── layout
│ ├── activity_about.xml
│ ├── activity_endpoint.xml
│ ├── activity_endpoint_settings.xml
│ ├── activity_main.xml
│ ├── activity_server.xml
│ ├── check_list_item.xml
│ ├── list_view_row_endpoint.xml
│ ├── list_view_row_log_message.xml
│ ├── list_view_row_server.xml
│ ├── notification_session.xml
│ ├── toggle_endpoint.xml
│ └── toggle_server.xml
│ ├── menu
│ ├── activity_connector.xml
│ ├── activity_endpoint_settings.xml
│ └── activity_main.xml
│ ├── raw
│ ├── agent.bks
│ └── ca.bks
│ ├── values-v11
│ └── styles.xml
│ ├── values-v14
│ └── styles.xml
│ ├── values
│ ├── attrs.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ ├── endpoint_headers.xml
│ └── preferences.xml
├── androidlib
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── java
│ └── com
│ │ └── WithSecure
│ │ └── androidlib
│ │ └── android
│ │ └── app
│ │ └── NotifyingService.java
│ └── res
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── layout
│ └── list_view_row_log_message.xml
│ ├── values-v11
│ └── styles.xml
│ ├── values-v14
│ └── styles.xml
│ └── values
│ ├── colors.xml
│ ├── strings.xml
│ └── styles.xml
├── build.gradle
├── docs
├── Overview.md
├── agent.md
└── jsolar.md
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── jsolar
├── CMakeLists.txt
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── cpp
│ └── libmstring
│ │ └── mstring.cpp
│ ├── java
│ └── com
│ │ └── WithSecure
│ │ └── jsolar
│ │ ├── api
│ │ ├── APIVersionException.java
│ │ ├── DeviceInfo.java
│ │ ├── Frame.java
│ │ ├── InvalidMessageException.java
│ │ ├── UnexpectedMessageException.java
│ │ ├── builders
│ │ │ ├── MessageFactory.java
│ │ │ ├── ReflectionResponseFactory.java
│ │ │ ├── SystemRequestFactory.java
│ │ │ └── SystemResponseFactory.java
│ │ ├── connectors
│ │ │ ├── Connection.java
│ │ │ ├── Connector.java
│ │ │ ├── Endpoint.java
│ │ │ ├── EndpointSocketFactory.java
│ │ │ ├── Server.java
│ │ │ └── ServerSocketFactory.java
│ │ ├── handlers
│ │ │ ├── MessageHandler.java
│ │ │ ├── ReflectionMessageHandler.java
│ │ │ └── SystemMessageHandler.java
│ │ ├── links
│ │ │ ├── Client.java
│ │ │ ├── Link.java
│ │ │ └── Server.java
│ │ ├── sessions
│ │ │ ├── Session.java
│ │ │ └── SessionCollection.java
│ │ └── transport
│ │ │ ├── SecureTransport.java
│ │ │ ├── SocketTransport.java
│ │ │ ├── Transport.java
│ │ │ └── TransportDisconnectedException.java
│ │ ├── connection
│ │ ├── AbstractConnection.java
│ │ ├── AbstractLink.java
│ │ ├── AbstractSession.java
│ │ ├── AbstractSessionCollection.java
│ │ └── SecureConnection.java
│ │ ├── logger
│ │ ├── LogMessage.java
│ │ ├── Logger.java
│ │ └── OnLogMessageListener.java
│ │ ├── reflection
│ │ ├── ObjectStore.java
│ │ ├── Reflector.java
│ │ └── types
│ │ │ ├── ReflectedArray.java
│ │ │ ├── ReflectedBinary.java
│ │ │ ├── ReflectedNull.java
│ │ │ ├── ReflectedObject.java
│ │ │ ├── ReflectedPrimitive.java
│ │ │ ├── ReflectedString.java
│ │ │ └── ReflectedType.java
│ │ └── util
│ │ ├── Shell.java
│ │ ├── Strings.java
│ │ └── Verify.java
│ ├── proto
│ └── protobuf.proto
│ └── res
│ ├── drawable-v24
│ └── ic_launcher_foreground.xml
│ ├── drawable
│ └── ic_launcher_background.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.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
│ ├── values
│ ├── colors.xml
│ └── strings.xml
│ └── xml
│ ├── backup_rules.xml
│ └── data_extraction_rules.xml
├── settings.gradle
└── tlslib
├── .gitignore
├── build.gradle
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── java
└── com
│ └── WithSecure
│ └── common
│ └── tls
│ ├── X509Fingerprint.java
│ └── trust_managers
│ ├── KeyStoreTrustManager.java
│ └── NaiveTrustManager.java
└── res
├── drawable-hdpi
└── ic_launcher.png
├── drawable-mdpi
└── ic_launcher.png
├── drawable-xhdpi
└── ic_launcher.png
├── values-v11
└── styles.xml
├── values-v14
└── styles.xml
└── values
├── strings.xml
└── styles.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Built application files
2 | /*/*/build/
3 | build/
4 | /*/.externalNativeBuild/
5 |
6 | # Local configuration file (sdk path, etc)
7 | local.properties
8 |
9 | # Gradle generated files
10 | .gradle/
11 |
12 | # Signing files
13 | .signing/
14 |
15 | # User-specific configurations
16 | .idea/libraries/
17 | .idea/workspace.xml
18 | .idea/tasks.xml
19 | .idea/.name
20 | .idea/compiler.xml
21 | .idea/copyright/profiles_settings.xml
22 | .idea/encodings.xml
23 | .idea/misc.xml
24 | .idea/modules.xml
25 | .idea/scopes/scope_settings.xml
26 | .idea/vcs.xml
27 | .idea/
28 | *.iml
29 | jdiesel/.cxx/
30 | */.cxx/*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2024, WithSecure
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions are met:
7 |
8 | 1. Redistributions of source code must retain the above copyright notice, this
9 | list of conditions and the following disclaimer.
10 |
11 | 2. Redistributions in binary form must reproduce the above copyright notice,
12 | this list of conditions and the following disclaimer in the documentation
13 | and/or other materials provided with the distribution.
14 |
15 | 3. Neither the name of the copyright holder nor the names of its
16 | contributors may be used to endorse or promote products derived from
17 | this software without specific prior written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | drozer-agent
2 | ======
3 |
4 | drozer (formerly Mercury) is a leading security testing framework for Android.
5 |
6 | drozer allows you to search for security vulnerabilities in apps and devices by assuming the role of an app and interacting with the Dalvik VM, other apps' IPC endpoints and the underlying OS.
7 |
8 | drozer provides tools to help you use, share and understand public Android exploits. It helps you to deploy a drozer Agent to a device through exploitation or social engineering. Using weasel (MWR's advanced exploitation payload) drozer is able to maximise the permissions available to it by installing a full agent, injecting a limited agent into a running process, or connecting a reverse shell to act as a Remote Access Tool (RAT).
9 |
10 | drozer is open source software, maintained by WithSecure, and can be downloaded from [https://labs.withsecure.com/tools/drozer]
11 |
12 |
13 | Building Using Android Studio
14 | -----------------------------
15 |
16 | 1. Open Android Studio and launch the Android SDK manager from it (Tools > Android > SDK Manager)
17 | 2. Check that these two components are installed and updated to the latest version. Install or upgrade
18 | them if necessary.
19 | 1. *Android SDK Platform Tools*
20 | 2. *Android Support Library*
21 | 3. *Google Play Services*
22 | 4. *Google Repository*
23 | 5. *Android NDK tools*
24 | 3. Return to Android Studio and select *Import Project*
25 | 4. Select the **drozer-agent** directory
26 | 5. Select "Import from existing model - Gradle"
27 |
28 | **IMPORTANT**: Once imported make sure the project has been synchronized with the Gradle files.
29 |
30 | License
31 | -------
32 |
33 | drozer is released under a 3-clause BSD License. See LICENSE for full details.
34 |
35 | Contacting the Project
36 | ----------------------
37 |
38 | drozer is Open Source software, made great by contributions from the community.
39 |
40 | For full source code, to report bugs, or to suggest features and contribute patches please see our Github project:
41 |
42 | [https://github.com/WithSecureLabs/drozer]
43 |
--------------------------------------------------------------------------------
/agent/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | namespace 'com.WithSecure.dz'
5 | compileSdkVersion 33
6 |
7 | defaultConfig {
8 | applicationId "com.withsecure.dz"
9 | minSdkVersion 17
10 | targetSdkVersion 33
11 | multiDexEnabled true
12 | }
13 |
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | debuggable true
19 | jniDebuggable true
20 | }
21 | debug {
22 | debuggable true
23 | jniDebuggable true
24 | minifyEnabled false
25 | }
26 | }
27 |
28 | sourceSets {
29 | main {
30 | java.srcDirs = ['src/main/java']
31 | res.srcDirs = ['src/main/res']
32 |
33 | }
34 | }
35 | lint {
36 | abortOnError false
37 | checkReleaseBuilds false
38 | }
39 | }
40 |
41 | dependencies {
42 | implementation 'com.android.support:multidex:2.0.1'
43 | implementation 'com.google.android.gms:play-services-safetynet:18.0.1'
44 | implementation 'com.google.android.material:material:1.7.0'
45 | implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
46 | androidTestImplementation 'androidx.test.ext:junit:1.1.4'
47 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
48 | implementation project(':jsolar')
49 | implementation project(':tlslib')
50 | implementation project(':androidlib')
51 | }
52 |
--------------------------------------------------------------------------------
/agent/lint.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/EndpointAdapter.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz;
2 |
3 | import com.WithSecure.dz.models.EndpointManager;
4 | import com.WithSecure.dz.views.EndpointListRowView;
5 | import com.WithSecure.jsolar.api.connectors.Endpoint;
6 |
7 | import android.content.Context;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.BaseAdapter;
11 |
12 | public class EndpointAdapter extends BaseAdapter {
13 |
14 | public interface OnEndpointSelectListener {
15 |
16 | public void onEndpointSelect(Endpoint endpoint);
17 | public void onEndpointToggle(Endpoint endpoint, boolean toggle);
18 |
19 | }
20 |
21 | private Context context = null;
22 | private EndpointManager endpoint_manager = null;
23 | private OnEndpointSelectListener endpoint_listener = null;
24 |
25 | public EndpointAdapter(Context context, EndpointManager endpoint_manager, OnEndpointSelectListener endpoint_listener) {
26 | this.context = context;
27 | this.endpoint_listener = endpoint_listener;
28 | this.endpoint_manager = endpoint_manager;
29 |
30 | this.endpoint_manager.setOnDatasetChangeListener(new EndpointManager.OnDatasetChangeListener() {
31 |
32 | @Override
33 | public void onDatasetChange(EndpointManager manager) {
34 | EndpointAdapter.this.notifyDataSetChanged();
35 | }
36 |
37 | });
38 | }
39 |
40 | @Override
41 | public int getCount() {
42 | return this.endpoint_manager.size();
43 | }
44 |
45 | @Override
46 | public Object getItem(int pos) {
47 | return this.endpoint_manager.all().get(pos);
48 | }
49 |
50 | @Override
51 | public long getItemId(int pos) {
52 | return pos;
53 | }
54 |
55 | @Override
56 | public View getView(int pos, View copyView, ViewGroup parent) {
57 | EndpointListRowView view = new EndpointListRowView(this.context);
58 | view.setEndpoint((Endpoint)this.getItem(pos));
59 | view.setEndpointListener(this.endpoint_listener);
60 |
61 | return view;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/activities/AboutActivity.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.activities;
2 |
3 | import com.WithSecure.dz.R;
4 |
5 | import android.os.Bundle;
6 | import android.app.Activity;
7 | import android.content.pm.PackageManager.NameNotFoundException;
8 | import android.view.Menu;
9 | import android.widget.TextView;
10 |
11 | public class AboutActivity extends Activity {
12 |
13 | private TextView description;
14 |
15 | private String getVersionName() {
16 | try {
17 | return this.getPackageManager().getPackageInfo(this.getPackageName(), 0).versionName;
18 | }
19 | catch(NameNotFoundException e) {
20 | throw new RuntimeException();
21 | }
22 | }
23 |
24 | @Override
25 | protected void onCreate(Bundle savedInstanceState) {
26 | super.onCreate(savedInstanceState);
27 | setContentView(R.layout.activity_about);
28 |
29 | this.description = (TextView)this.findViewById(R.id.about_description);
30 | this.description.setText(String.format(this.getString(R.string.about_description), this.getVersionName()));
31 | }
32 |
33 | @Override
34 | public boolean onCreateOptionsMenu(Menu menu) {
35 | return false;
36 | }
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/activities/ConnectorActivity.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.activities;
2 |
3 | import java.lang.ref.WeakReference;
4 |
5 | import com.WithSecure.dz.Agent;
6 | import com.WithSecure.dz.R;
7 | import com.WithSecure.jsolar.api.connectors.Connector;
8 |
9 | import android.app.Activity;
10 | import android.app.AlertDialog;
11 | import android.app.Dialog;
12 | import android.content.Context;
13 | import android.content.DialogInterface;
14 | import android.os.Bundle;
15 | import android.os.Handler;
16 | import android.os.Message;
17 | import android.view.Menu;
18 | import android.view.MenuItem;
19 |
20 | public abstract class ConnectorActivity extends Activity {
21 |
22 | public static class IncomingFingerprintHandler extends Handler {
23 |
24 | private final WeakReference context;
25 |
26 | public IncomingFingerprintHandler(Context context) {
27 | this.context = new WeakReference(context);
28 | }
29 |
30 | @Override
31 | public void handleMessage(Message msg) {
32 | ConnectorActivity context = (ConnectorActivity)this.context.get();
33 | Bundle data = msg.getData();
34 |
35 | if(data.getString(Connector.CONNECTOR_SSL_FINGERPRINT) != null)
36 | context.receiveFingerprint(data.getString(Connector.CONNECTOR_SSL_FINGERPRINT));
37 | else
38 | context.receiveFingerprint(context.getString(R.string.ssl_no_fingerprint));
39 | }
40 |
41 | }
42 |
43 | protected Dialog createInformationDialog(int titleId, int messageId) {
44 | return new AlertDialog.Builder(this)
45 | .setTitle(titleId)
46 | .setMessage(messageId)
47 | .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
48 |
49 | public void onClick(DialogInterface dialog, int id) {}
50 |
51 | })
52 | .create();
53 | }
54 |
55 | protected Dialog createInformationDialog(int titleId, String message) {
56 | return new AlertDialog.Builder(this)
57 | .setTitle(titleId)
58 | .setMessage(message)
59 | .setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
60 |
61 | public void onClick(DialogInterface dialog, int id) {}
62 |
63 | })
64 | .create();
65 | }
66 |
67 | @Override
68 | public boolean onCreateOptionsMenu(Menu menu) {
69 | getMenuInflater().inflate(R.menu.activity_connector, menu);
70 | return true;
71 | }
72 |
73 | @Override
74 | public boolean onOptionsItemSelected(MenuItem item) {
75 | switch(item.getItemId()) {
76 | case R.id.show_fingerprint:
77 | this.showFingerprintDialog();
78 | return true;
79 |
80 | case R.id.refresh_status:
81 | this.refreshStatus();
82 | return true;
83 |
84 | default:
85 | return super.onOptionsItemSelected(item);
86 | }
87 | }
88 |
89 | @Override
90 | protected void onPause() {
91 | super.onPause();
92 |
93 | Agent.getInstance().unbindServices();
94 | }
95 |
96 | @Override
97 | protected void onResume() {
98 | super.onResume();
99 |
100 | Agent.getInstance().bindServices();
101 | }
102 |
103 | public abstract void receiveFingerprint(String fingerprint);
104 | protected abstract void refreshStatus();
105 | protected abstract void showFingerprintDialog();
106 |
107 | }
108 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/activities/StartBroadcastActivity.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.activities;
2 |
3 | import android.app.Activity;
4 | import android.content.ComponentName;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.os.Parcelable;
8 | import android.util.Log;
9 |
10 | import java.util.ArrayList;
11 |
12 | public class StartBroadcastActivity extends Activity {
13 |
14 | public void onCreate(Bundle bundle) {
15 | super.onCreate(bundle);
16 | startChooser(getIntent());
17 | finish();
18 | }
19 |
20 | /* access modifiers changed from: protected */
21 | public void onResume() {
22 | super.onResume();
23 | }
24 |
25 | /* access modifiers changed from: protected */
26 | public void onDestroy() {
27 | super.onDestroy();
28 | }
29 |
30 | /* access modifiers changed from: protected */
31 | public void onRestart() {
32 | super.onRestart();
33 | }
34 |
35 | /* access modifiers changed from: protected */
36 | public void onPause() {
37 | super.onPause();
38 | }
39 |
40 | private void startChooser(Intent intent) {
41 | if (intent != null && intent.getExtras().containsKey("yayintentyay")) {
42 | try {
43 | ArrayList arrayList = new ArrayList<>();
44 | arrayList.add(new ComponentName(this.getPackageName(), StartBroadcastActivity.class.getName()));
45 |
46 | Intent yayparcelableyay = intent.getParcelableExtra("yayintentyay");
47 | Intent createChooser = Intent.createChooser((Intent) yayparcelableyay, "Share");
48 |
49 | createChooser.putExtra("android.intent.extra.EXCLUDE_COMPONENTS", (Parcelable[]) arrayList.toArray(new Parcelable[0]));
50 |
51 | createChooser.setComponent(yayparcelableyay.getComponent());
52 | createChooser.putExtras(yayparcelableyay.getExtras());
53 | createChooser.setAction(yayparcelableyay.getAction());
54 |
55 | hooking(createChooser);
56 |
57 | startActivity(createChooser);
58 | } catch (Exception e) {
59 | Log.d("yaytagyay", e.getMessage());
60 | }
61 | }
62 | }
63 |
64 | private void hooking(Intent intent){
65 | Log.i("yaytagyay", "intent");
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/helpers/IntentProxyToContentProvider.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.helpers;
2 |
3 | import android.app.Activity;
4 | import android.net.Uri;
5 | import android.os.Bundle;
6 |
7 | import java.io.File;
8 | import java.io.FileNotFoundException;
9 | import java.io.FileOutputStream;
10 | import java.io.InputStream;
11 |
12 | public class IntentProxyToContentProvider extends Activity {
13 |
14 | // This class is meant to help download files from unexported Content Providers
15 | // Assuming the unexported Content Provider has GrantURIPermissions set to True
16 | // Make sure the victim app is calling this activity
17 | //
18 | // Example of what the victim app should be doing:
19 | // Intent intent = new Intent();
20 | // intent.setComponent(new ComponentName("com.mwr.dz", "com.mwr.dz.helpers.IntentProxyToContentProvider");
21 | // intent.setFlags(195);
22 | // intent.setData(Uri.parse("content://");
23 | // startActivity(intent);
24 | //
25 | // Any file downloaded will be saved to Drozer's private file directory
26 | // /data/data/com.mwr.dz/files/
27 |
28 | String filename = "yayoutputyay"; // save file as "yayoutputyay"
29 |
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | Uri uri = Uri.parse(getIntent().getDataString()); // Get the Uri for the unexported content provider
33 | if (getIntent().getStringExtra("filename") != null) {
34 | filename = getIntent().getStringExtra("filename"); // if intent has String extra "filename", save file as this name
35 | }
36 | try {
37 | InputStream input = getContentResolver().openInputStream(uri); // Reach out to the unexported Content Provider
38 | File file = new File(getFilesDir(), filename); // make local file
39 | FileOutputStream output = new FileOutputStream(file); // also make local file
40 | try {
41 | byte[] buf = new byte[1024];
42 | int len;
43 | while ((len = input.read(buf)) > 0) {
44 | output.write(buf, 0, len); // write local file from the file pulled from content provider
45 | }
46 | } catch (Exception e) {
47 | e.printStackTrace();
48 | } finally {
49 | try {
50 | if (input != null)
51 | input.close();
52 | if (output != null)
53 | output.close();
54 | } catch (Exception e) {
55 | e.printStackTrace();
56 | }
57 | }
58 | } catch (FileNotFoundException e) {
59 | e.printStackTrace();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/models/ServerSettings.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.models;
2 |
3 | import android.content.SharedPreferences;
4 | import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
5 |
6 | import com.WithSecure.dz.Agent;
7 | import com.WithSecure.jsolar.api.connectors.Server;
8 |
9 | public class ServerSettings implements OnSharedPreferenceChangeListener {
10 |
11 | private Server server;
12 |
13 | private char[] getKeyPassword() {
14 | return this.getSettings().getString(Server.SERVER_KEY_PASSWORD, "drozer").toCharArray();
15 | }
16 |
17 | private char[] getKeyStorePassword() {
18 | return this.getSettings().getString(Server.SERVER_KEYSTORE_PASSWORD, "drozer").toCharArray();
19 | }
20 |
21 | private String getKeyStorePath() {
22 | return this.getSettings().getString(Server.SERVER_KEYSTORE_PATH, "/data/data/com.withsecure.dz/files/drozer.bks");
23 | }
24 |
25 | private String getPassword() {
26 | return this.getSettings().getString(Server.SERVER_PASSWORD, "");
27 | }
28 |
29 | private int getPort() {
30 | return Integer.parseInt(this.getSettings().getString(Server.SERVER_PORT, "31415"));
31 | }
32 |
33 | private SharedPreferences getSettings() {
34 | return Agent.getInstance().getSettings();
35 | }
36 |
37 | private boolean isSSL() {
38 | return this.getSettings().getBoolean(Server.SERVER_SSL, false);
39 | }
40 |
41 | public void load(Server server) {
42 | this.server = server;
43 |
44 | server.setPort(this.getPort());
45 | server.setPassword(this.getPassword());
46 | server.setSSL(this.isSSL());
47 |
48 | if(this.isSSL()) {
49 | server.setSSL(this.isSSL());
50 | server.setKeyStorePath(this.getKeyStorePath());
51 | server.setKeyStorePassword(this.getKeyStorePassword());
52 | server.setKeyPassword(this.getKeyPassword());
53 | }
54 |
55 | server.resetKeyManagerFactory();
56 |
57 | this.getSettings().registerOnSharedPreferenceChangeListener(this);
58 | }
59 |
60 | @Override
61 | public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
62 | if(key.equals(Server.SERVER_PORT))
63 | this.server.setPort(this.getPort());
64 | if(key.equals(Server.SERVER_PASSWORD))
65 | this.server.setPassword(this.getPassword());
66 |
67 | if(key.equals(Server.SERVER_SSL)) {
68 | this.server.setSSL(this.isSSL());
69 | server.setKeyStorePath(this.getKeyStorePath());
70 | server.setKeyStorePassword(this.getKeyStorePassword());
71 | server.setKeyPassword(this.getKeyPassword());
72 | }
73 |
74 | if(key.equals(Server.SERVER_KEYSTORE_PATH))
75 | server.setKeyStorePath(this.getKeyStorePath());
76 | if(key.equals(Server.SERVER_KEYSTORE_PASSWORD))
77 | server.setKeyStorePassword(this.getKeyStorePassword());
78 | if(key.equals(Server.SERVER_KEY_PASSWORD))
79 | server.setKeyPassword(this.getKeyPassword());
80 | }
81 |
82 | public boolean save(Server server) {
83 | SharedPreferences.Editor editor = Agent.getInstance().getSettings().edit();
84 |
85 | editor.remove(Server.SERVER_PORT);
86 | editor.putString(Server.SERVER_PORT, Integer.valueOf(this.getPort()).toString());
87 |
88 | return editor.commit();
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/providers/Provider.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.providers;
2 |
3 | import android.content.ComponentName;
4 | import android.content.ContentProvider;
5 | import android.content.ContentValues;
6 | import android.content.Context;
7 | import android.content.Intent;
8 | import android.database.Cursor;
9 | import android.net.Uri;
10 | import android.util.Log;
11 |
12 | import androidx.annotation.NonNull;
13 | import androidx.annotation.Nullable;
14 |
15 | public class Provider extends ContentProvider {
16 |
17 |
18 | @Override
19 | public boolean onCreate() {
20 | return false;
21 | }
22 |
23 | @Nullable
24 | @Override
25 | public Cursor query(@NonNull Uri uri, @Nullable String[] strings, @Nullable String s, @Nullable String[] strings1, @Nullable String s1) {
26 | Context context = this.getContext();
27 | Intent yayintentyay = new Intent("android.intent.action.MAIN");
28 | ComponentName yaycnyay = new ComponentName(context.getPackageName(), "com.WithSecure.dz.activities.MainActivity");
29 | yayintentyay.setComponent(yaycnyay);
30 | yayintentyay.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
31 | try {
32 | context.startActivity(yayintentyay);
33 | } catch (Exception e) {
34 | Log.d("yaytagyay", e.getMessage());
35 | }
36 | return null;
37 | }
38 |
39 | @Nullable
40 | @Override
41 | public String getType(@NonNull Uri uri) {
42 | return null;
43 | }
44 |
45 | @Nullable
46 | @Override
47 | public Uri insert(@NonNull Uri uri, @Nullable ContentValues contentValues) {
48 | return null;
49 | }
50 |
51 | @Override
52 | public int delete(@NonNull Uri uri, @Nullable String s, @Nullable String[] strings) {
53 | return 0;
54 | }
55 |
56 | @Override
57 | public int update(@NonNull Uri uri, @Nullable ContentValues contentValues, @Nullable String s, @Nullable String[] strings) {
58 | return 0;
59 | }
60 | }
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/receivers/StartMainActivityReceiver.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.receivers;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.ComponentName;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.util.Log;
8 |
9 | public class StartMainActivityReceiver extends BroadcastReceiver {
10 |
11 | @Override
12 | public void onReceive(Context context, Intent intent) {
13 | Intent yayintentyay = new Intent("android.intent.action.MAIN");
14 | ComponentName yaycnyay = new ComponentName(context.getPackageName(), "com.WithSecure.dz.activities.MainActivity");
15 | yayintentyay.setComponent(yaycnyay);
16 | yayintentyay.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
17 | try {
18 | context.startActivity(yayintentyay);
19 | } catch (Exception e) {
20 | Log.d("yaytagyay", e.getMessage());
21 | }
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/receivers/StartServiceReceiver.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.receivers;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.ComponentName;
5 | import android.content.Context;
6 | import android.content.Intent;
7 |
8 | public class StartServiceReceiver extends BroadcastReceiver {
9 |
10 | public static final String PWN_INTENT = "com.withsecure.dz.PWN";
11 |
12 | @Override
13 | public void onReceive(Context context, Intent intent) {
14 | Intent start_service = new Intent();
15 | start_service.putExtras(intent);
16 |
17 | if(intent.getCategories().contains("com.WithSecure.dz.START_EMBEDDED")) {
18 | start_service.addCategory("com.WithSecure.dz.START_EMBEDDED");
19 | start_service.setComponent(new ComponentName(context.getPackageName(), "com.WithSecure.dz.services.ServerService"));
20 | }
21 | else {
22 | if(intent.getCategories().contains("com.WithSecure.dz.CREATE_ENDPOINT"))
23 | start_service.addCategory("com.WithSecure.dz.CREATE_ENDPOINT");
24 | if(intent.getCategories().contains("com.WithSecure.dz.START_ENDPOINT"))
25 | start_service.addCategory("com.WithSecure.dz.START_ENDPOINT");
26 |
27 | start_service.setComponent(new ComponentName(context.getPackageName(), "com.WithSecure.dz.services.ClientService"));
28 | }
29 |
30 | context.startService(start_service);
31 | }
32 |
33 | }
34 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/service_connectors/ClientServiceConnection.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.service_connectors;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.ServiceConnection;
6 | import android.os.Bundle;
7 | import android.os.IBinder;
8 | import android.os.Message;
9 | import android.os.Messenger;
10 | import android.os.RemoteException;
11 | import android.util.Log;
12 |
13 | import com.WithSecure.dz.Agent;
14 | import com.WithSecure.dz.services.ClientService;
15 | import com.WithSecure.jsolar.api.connectors.Endpoint;
16 |
17 | public class ClientServiceConnection implements ServiceConnection {
18 |
19 | private Messenger service = null;
20 | private boolean bound = false;
21 |
22 | public boolean isBound() {
23 | return this.bound;
24 | }
25 |
26 | public void getDetailedEndpointStatus(int id, Messenger replyTo) throws RemoteException {
27 | Bundle data = new Bundle();
28 |
29 | data.putInt(Endpoint.ENDPOINT_ID, id);
30 |
31 | Message msg = Message.obtain(null, ClientService.MSG_GET_DETAILED_ENDPOINT_STATUS);
32 | msg.replyTo = Agent.getInstance().getMessenger();
33 | msg.setData(data);
34 |
35 | this.send(msg);
36 | }
37 |
38 | public void getEndpointStatuses(Messenger replyTo) throws RemoteException {
39 | Message msg = Message.obtain(null, ClientService.MSG_GET_ENDPOINTS_STATUS);
40 | msg.replyTo = replyTo;
41 |
42 | this.send(msg);
43 | }
44 |
45 | public void getPeerFingerprint(int id, Messenger replyTo) throws RemoteException {
46 | Bundle data = new Bundle();
47 | data.putBoolean("ctrl:no_cache_messenger", true);
48 | data.putInt(Endpoint.ENDPOINT_ID, id);
49 |
50 | Message msg = Message.obtain(null, ClientService.MSG_GET_SSL_FINGERPRINT);
51 | msg.replyTo = replyTo;
52 | msg.setData(data);
53 |
54 | this.send(msg);
55 | }
56 |
57 | @Override
58 | public void onServiceConnected(ComponentName className, IBinder service) {
59 | this.service = new Messenger(service);
60 | this.bound = true;
61 |
62 | if(Agent.getInstance().getSettings().getBoolean("restore_after_crash", true)){
63 | for(Endpoint e : Agent.getInstance().getEndpointManager().all()){
64 | if(e.isActive()){
65 | try {
66 | Log.d("ClientService", "Resuming connection to endpoint...");
67 | Agent.getInstance().getClientService().startEndpoint(e, Agent.getInstance().getMessenger());
68 | } catch (RemoteException re) {
69 | re.printStackTrace();
70 | }
71 | }
72 | }
73 | }
74 |
75 | }
76 |
77 | @Override
78 | public void onServiceDisconnected(ComponentName className) {
79 | this.service = null;
80 | this.bound = false;
81 | }
82 |
83 | protected void send(Message msg) throws RemoteException {
84 | this.service.send(msg);
85 | }
86 |
87 | public void startEndpoint(Endpoint endpoint, Messenger replyTo) throws RemoteException {
88 | Bundle data = new Bundle();
89 | data.putInt(Endpoint.ENDPOINT_ID, endpoint.getId());
90 |
91 | Message msg = Message.obtain(null, ClientService.MSG_START_ENDPOINT);
92 | msg.replyTo = replyTo;
93 | msg.setData(data);
94 |
95 | this.send(msg);
96 |
97 | endpoint.enabled = true;
98 | endpoint.notifyObservers();
99 | }
100 |
101 | public void stopEndpoint(Endpoint endpoint, Messenger replyTo) throws RemoteException {
102 | Bundle data = new Bundle();
103 |
104 | data.putInt(Endpoint.ENDPOINT_ID, endpoint.getId());
105 |
106 | Message msg = Message.obtain(null, ClientService.MSG_STOP_ENDPOINT);
107 | msg.replyTo = replyTo;
108 | msg.setData(data);
109 |
110 | this.send(msg);
111 |
112 | endpoint.enabled = false;
113 | endpoint.notifyObservers();
114 | }
115 |
116 | public void unbind(Context context) {
117 | if(this.bound) {
118 | context.unbindService(this);
119 | this.bound = false;
120 | }
121 | }
122 |
123 | }
124 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/service_connectors/IncomingReplyHandler.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.service_connectors;
2 |
3 | import java.lang.ref.WeakReference;
4 |
5 | import android.os.Bundle;
6 | import android.os.Handler;
7 | import android.os.Message;
8 |
9 | import com.WithSecure.dz.Agent;
10 | import com.WithSecure.dz.services.ClientService;
11 | import com.WithSecure.dz.services.ConnectorService;
12 | import com.WithSecure.dz.services.ServerService;
13 | import com.WithSecure.jsolar.api.connectors.Connector;
14 | import com.WithSecure.jsolar.api.connectors.Endpoint;
15 | import com.WithSecure.jsolar.logger.LogMessage;
16 |
17 | public class IncomingReplyHandler extends Handler {
18 |
19 | private final WeakReference agent;
20 |
21 | public IncomingReplyHandler(Agent agent) {
22 | this.agent = new WeakReference(agent);
23 | }
24 |
25 | @Override
26 | public void handleMessage(Message msg) {
27 | Agent agent = this.agent.get();
28 | Bundle data = msg.getData();
29 |
30 | switch(msg.what) {
31 | case ClientService.MSG_GET_DETAILED_ENDPOINT_STATUS:
32 | agent.getEndpointManager().get(data.getInt(Endpoint.ENDPOINT_ID)).setDetailedStatus(data);
33 | break;
34 |
35 | case ClientService.MSG_GET_ENDPOINTS_STATUS:
36 | for(Endpoint e : agent.getEndpointManager().all())
37 | if(data.containsKey("endpoint-" + e.getId()))
38 | e.setStatus(Endpoint.Status.values()[data.getInt("endpoint-" + e.getId())]);
39 | break;
40 |
41 | case ServerService.MSG_GET_DETAILED_SERVER_STATUS:
42 | agent.getServerParameters().setDetailedStatus(data);
43 | break;
44 |
45 | case ServerService.MSG_GET_SERVER_STATUS:
46 | agent.getServerParameters().setStatus(Connector.Status.values()[data.getInt("server")]);
47 | break;
48 |
49 | case ConnectorService.MSG_LOG_MESSAGE:
50 | LogMessage log_message = new LogMessage(data.getBundle(Connector.CONNECTOR_LOG_MESSAGE));
51 | if (data.containsKey(Endpoint.ENDPOINT_ID))
52 | agent.getEndpointManager().get(data.getInt(Endpoint.ENDPOINT_ID)).getLogger().log(log_message);
53 | else
54 | agent.getServerParameters().getLogger().log(log_message);
55 | break;
56 |
57 | default:
58 | super.handleMessage(msg);
59 | }
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/service_connectors/ServerServiceConnection.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.service_connectors;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.ServiceConnection;
6 | import android.content.SharedPreferences.Editor;
7 | import android.os.Bundle;
8 | import android.os.IBinder;
9 | import android.os.Message;
10 | import android.os.Messenger;
11 | import android.os.RemoteException;
12 |
13 | import com.WithSecure.dz.Agent;
14 | import com.WithSecure.dz.services.ServerService;
15 | import com.WithSecure.jsolar.api.connectors.Server;
16 |
17 | public class ServerServiceConnection implements ServiceConnection {
18 |
19 | private Messenger service = null;
20 | private boolean bound = false;
21 |
22 | public void getDetailedServerStatus(Messenger replyTo) throws RemoteException {
23 | Message msg = Message.obtain(null, ServerService.MSG_GET_DETAILED_SERVER_STATUS);
24 | msg.replyTo = replyTo;
25 |
26 | this.send(msg);
27 | }
28 |
29 | public void getHostFingerprint(Messenger replyTo) throws RemoteException {
30 | Bundle data = new Bundle();
31 | data.putBoolean("ctrl:no_cache_messenger", true);
32 |
33 | Message msg = Message.obtain(null, ServerService.MSG_GET_SSL_FINGERPRINT);
34 | msg.replyTo = replyTo;
35 | msg.setData(data);
36 |
37 | this.send(msg);
38 | }
39 |
40 | public void getServerStatus(Messenger replyTo) throws RemoteException {
41 | Message msg = Message.obtain(null, ServerService.MSG_GET_SERVER_STATUS);
42 | msg.replyTo = replyTo;
43 |
44 | this.send(msg);
45 | }
46 |
47 | public boolean isBound() {
48 | return this.bound;
49 | }
50 |
51 | @Override
52 | public void onServiceConnected(ComponentName className, IBinder service) {
53 | this.service = new Messenger(service);
54 | this.bound = true;
55 | if(Agent.getInstance().getSettings().getBoolean("localServerEnabled", false) && Agent.getInstance().getSettings().getBoolean("restore_after_crash", true)){
56 | try {
57 | ServerServiceConnection ssc = Agent.getInstance().getServerService();
58 | Server server = Agent.getInstance().getServerParameters();
59 | Messenger messenger = Agent.getInstance().getMessenger();
60 |
61 | ssc.startServer(server, messenger);
62 | } catch (RemoteException e) {
63 | e.printStackTrace();
64 | }
65 | }
66 | }
67 |
68 | @Override
69 | public void onServiceDisconnected(ComponentName className) {
70 | this.service = null;
71 | this.bound = false;
72 | }
73 |
74 | protected void send(Message msg) throws RemoteException {
75 | this.service.send(msg);
76 | }
77 |
78 | public void startServer(Server server, Messenger replyTo) throws RemoteException {
79 | Message msg = Message.obtain(null, ServerService.MSG_START_SERVER);
80 | msg.replyTo = replyTo;
81 |
82 | this.send(msg);
83 |
84 | Editor edit = Agent.getInstance().getSettings().edit();
85 | edit.putBoolean("localServerEnabled", true);
86 | edit.apply();
87 |
88 | server.enabled = true;
89 | server.notifyObservers();
90 | }
91 |
92 | public void stopServer(Server server, Messenger replyTo) throws RemoteException {
93 | Message msg = Message.obtain(null, ServerService.MSG_STOP_SERVER);
94 | msg.replyTo = replyTo;
95 |
96 | this.send(msg);
97 |
98 | Editor edit = Agent.getInstance().getSettings().edit();
99 | edit.putBoolean("localServerEnabled", false);
100 | edit.apply();
101 |
102 | server.enabled = false;
103 | server.notifyObservers();
104 | }
105 |
106 | public void unbind(Context context) {
107 | if(this.bound) {
108 | context.unbindService(this);
109 | this.bound = false;
110 | }
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/service_connectors/SessionServiceConnection.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.service_connectors;
2 |
3 | import android.content.ComponentName;
4 | import android.content.Context;
5 | import android.content.ServiceConnection;
6 | import android.os.IBinder;
7 | import android.os.Messenger;
8 | import android.os.RemoteException;
9 |
10 | import com.WithSecure.dz.services.SessionService;
11 |
12 | public class SessionServiceConnection implements ServiceConnection {
13 |
14 | private Messenger service = null;
15 | private boolean bound = false;
16 |
17 | public boolean isBound() {
18 | return this.bound;
19 | }
20 |
21 | public void notifySessionStarted(String sessionId) {
22 | try {
23 | this.send(android.os.Message.obtain(null, SessionService.MSG_START_SESSION, sessionId));
24 | }
25 | catch(RemoteException e) {}
26 | }
27 |
28 | public void notifySessionStopped(String sessionId) {
29 | try {
30 | this.send(android.os.Message.obtain(null, SessionService.MSG_STOP_SESSION, sessionId));
31 | }
32 | catch(RemoteException e) {}
33 | }
34 |
35 | @Override
36 | public void onServiceConnected(ComponentName className, IBinder service) {
37 | this.service = new Messenger(service);
38 | this.bound = true;
39 | }
40 |
41 | @Override
42 | public void onServiceDisconnected(ComponentName className) {
43 | this.service = null;
44 | this.bound = false;
45 | }
46 |
47 | public void send(android.os.Message msg) throws RemoteException {
48 | this.service.send(msg);
49 | }
50 |
51 | public void unbind(Context context) {
52 | if(this.bound) {
53 | context.unbindService(this);
54 | this.bound = false;
55 | }
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/services/ConnectorService.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.services;
2 |
3 | import java.lang.ref.WeakReference;
4 | import java.util.ArrayList;
5 |
6 | import com.WithSecure.jsolar.api.connectors.Connector;
7 | import com.WithSecure.jsolar.api.connectors.Endpoint;
8 | import com.WithSecure.jsolar.logger.LogMessage;
9 | import com.WithSecure.jsolar.logger.Logger;
10 | import com.WithSecure.jsolar.logger.OnLogMessageListener;
11 |
12 | import android.app.Service;
13 | import android.content.Intent;
14 | import android.os.Bundle;
15 | import android.os.Handler;
16 | import android.os.IBinder;
17 | import android.os.Message;
18 | import android.os.Messenger;
19 | import android.os.RemoteException;
20 |
21 | public abstract class ConnectorService extends Service implements OnLogMessageListener {
22 |
23 | public static final int MSG_LOG_MESSAGE = 1;
24 |
25 | /**
26 | * IncomingHandler is used to process all messages received by the
27 | * ConnectorService. It stores a reference to the incoming messenger (if
28 | * applicable) and hands the message off to the implementation for
29 | * processing.
30 | */
31 | private static class IncomingHandler extends Handler {
32 |
33 | private final WeakReference service;
34 |
35 | public IncomingHandler(ConnectorService service) {
36 | this.service = new WeakReference(service);
37 | }
38 |
39 | @Override
40 | public void handleMessage(Message msg) {
41 | Bundle data = msg.getData();
42 | ConnectorService service = this.service.get();
43 |
44 | if(data == null || !data.getBoolean("ctrl:no_cache_messenger"))
45 | service.cacheMessenger(msg.replyTo);
46 |
47 | service.handleMessage(msg);
48 | }
49 |
50 | }
51 |
52 | private final Messenger messenger = new Messenger(new IncomingHandler(this));
53 | private final ArrayList messengers = new ArrayList();
54 | protected static boolean running = false;
55 |
56 | /**
57 | * Broadcasts a bundle of data, as a log message, to every messenger that has
58 | * previously sent us a message.
59 | */
60 | protected void broadcastLogMessageBundle(Bundle data) {
61 | Message message = Message.obtain(null, ConnectorService.MSG_LOG_MESSAGE);
62 | message.setData(data);
63 |
64 | this.sendToAllMessengers(message);
65 | }
66 |
67 | /**
68 | * Stores a reference to a Messenger, if we haven't already stored it.
69 | */
70 | public void cacheMessenger(Messenger messenger) {
71 | if(!this.messengers.contains(messenger))
72 | this.messengers.add(messenger);
73 | }
74 |
75 | /**
76 | * handleMessage() is handed every message that is passed to this service,
77 | * to process and send any replies.
78 | *
79 | * Override in an implementation of Connector service.
80 | */
81 | public abstract void handleMessage(Message msg);
82 |
83 | @Override
84 | public IBinder onBind(Intent intent) {
85 | return this.messenger.getBinder();
86 | }
87 |
88 | @Override
89 | public void onLogMessage(Logger logger, LogMessage message) {
90 | Bundle data = new Bundle();
91 | data.putBundle(Connector.CONNECTOR_LOG_MESSAGE, message.toBundle());
92 |
93 | Connector connector = logger.getOwner();
94 |
95 | if(connector instanceof Endpoint)
96 | data.putInt(Endpoint.ENDPOINT_ID, ((Endpoint)connector).getId());
97 | this.broadcastLogMessageBundle(data);
98 | }
99 |
100 | @Override
101 | public int onStartCommand(Intent intent, int flags, int startId) {
102 | return START_REDELIVER_INTENT;
103 | }
104 |
105 | /**
106 | * Attempt to deliver a Message to all messengers that have previously sent
107 | * a message to this service, without specifying not to cache their handle.
108 | */
109 | protected void sendToAllMessengers(Message msg) {
110 | for(Messenger m : this.messengers) {
111 | try {
112 | m.send(msg);
113 | }
114 | catch(RemoteException e) {}
115 | }
116 | }
117 |
118 | }
119 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/services/SessionService.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.services;
2 |
3 | import java.lang.ref.WeakReference;
4 | import java.util.HashSet;
5 |
6 | import android.app.PendingIntent;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.ServiceConnection;
10 | import android.os.Handler;
11 | import android.os.IBinder;
12 | import android.os.Message;
13 | import android.os.Messenger;
14 | import android.widget.RemoteViews;
15 |
16 | import com.WithSecure.androidlib.android.app.NotifyingService;
17 | import com.WithSecure.dz.R;
18 | import com.WithSecure.dz.activities.MainActivity;
19 |
20 | public class SessionService extends NotifyingService {
21 |
22 | public static final int MSG_START_SESSION = 1;
23 | public static final int MSG_STOP_SESSION = 2;
24 |
25 | private final Messenger messenger = new Messenger(new IncomingHandler(this));
26 | private static boolean running = false;
27 | private HashSet sessions = new HashSet();
28 |
29 | static class IncomingHandler extends Handler {
30 |
31 | private final WeakReference service;
32 |
33 | public IncomingHandler(SessionService service) {
34 | this.service = new WeakReference(service);
35 | }
36 |
37 | @Override
38 | public void handleMessage(Message msg) {
39 | SessionService service = this.service.get();
40 | String session_id = (String)msg.obj;
41 |
42 | switch(msg.what) {
43 | case MSG_START_SESSION:
44 | service.add(session_id);
45 |
46 | service.updateNotification();
47 | break;
48 |
49 | case MSG_STOP_SESSION:
50 | service.remove(session_id);
51 |
52 | service.updateNotification();
53 | break;
54 |
55 | default:
56 | super.handleMessage(msg);
57 | }
58 | }
59 |
60 | }
61 |
62 | public void add(String session_id) {
63 | this.sessions.add(session_id);
64 | }
65 |
66 | @Override
67 | public IBinder onBind(Intent arg0) {
68 | return this.messenger.getBinder();
69 | }
70 |
71 | @Override
72 | public void onCreate() {
73 | super.onCreate();
74 |
75 | SessionService.running = true;
76 | }
77 |
78 | @Override
79 | public void onDestroy() {
80 | SessionService.running = false;
81 | }
82 |
83 | @Override
84 | protected void onCreateNotification(RemoteViews view) {
85 | view.setImageViewResource(R.id.cs_notification_icon, R.drawable.ic_notification);
86 | view.setTextViewText(R.id.cs_notification_ticker, getString(R.string.session_connected));
87 | }
88 |
89 | public void remove(String session_id) {
90 | this.sessions.remove(session_id);
91 | }
92 |
93 | public static void startAndBindToService(Context context, ServiceConnection serviceConnection) {
94 | if(!SessionService.running)
95 | context.startService(new Intent(context, SessionService.class));
96 |
97 | Intent intent = new Intent(context, SessionService.class);
98 | context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
99 | }
100 |
101 | private void updateNotification() {
102 | if(!this.sessions.isEmpty())
103 | this.showNotification(this.getString(R.string.app_name), R.layout.notification_session, R.drawable.ic_notification, PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0));
104 | else
105 | this.hideNotification(this.getString(R.string.app_name), R.layout.notification_session);
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/views/CheckListItemView.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.views;
2 |
3 | import com.WithSecure.dz.R;
4 |
5 | import android.content.Context;
6 | import android.content.res.TypedArray;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 | import android.widget.ImageView;
10 | import android.widget.LinearLayout;
11 | import android.widget.TextView;
12 |
13 | public class CheckListItemView extends LinearLayout {
14 |
15 | private TextView label = null;
16 | private ImageView status = null;
17 |
18 | public CheckListItemView(Context context) {
19 | super(context);
20 |
21 | this.setUpView();
22 | }
23 |
24 | public CheckListItemView(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 |
27 | this.setUpView();
28 |
29 | TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.CheckListItemView);
30 |
31 | this.setLabel(a.getString(R.styleable.CheckListItemView_text));
32 | this.setStatus(a.getBoolean(R.styleable.CheckListItemView_defaultValue, false));
33 |
34 | a.recycle();
35 | }
36 |
37 | public void setLabel(int resId) {
38 | this.setLabel(this.getContext().getString(resId));
39 | }
40 |
41 | public void setLabel(String text) {
42 | this.label.setText(text);
43 | }
44 |
45 | public void setStatus(boolean status) {
46 | this.status.setImageResource(status ? android.R.drawable.button_onoff_indicator_on : android.R.drawable.button_onoff_indicator_off);
47 | }
48 |
49 | private void setUpView() {
50 | this.addView(View.inflate(this.getContext(), R.layout.check_list_item, null));
51 |
52 | this.label = (TextView)this.findViewById(R.id.check_list_item_label);
53 | this.status = (ImageView)this.findViewById(R.id.check_list_item_status);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/views/ConnectorStatusIndicator.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.views;
2 |
3 | import java.util.Observable;
4 | import java.util.Observer;
5 |
6 | import com.WithSecure.dz.R;
7 | import com.WithSecure.jsolar.api.connectors.Connector;
8 |
9 | import android.content.Context;
10 | import android.graphics.drawable.AnimationDrawable;
11 | import android.util.AttributeSet;
12 | import android.view.Gravity;
13 | import android.widget.ImageView;
14 | import android.widget.LinearLayout;
15 |
16 | public class ConnectorStatusIndicator extends LinearLayout implements Observer {
17 |
18 | private AnimationDrawable animation = null;
19 | private Connector connector_parameters = null;
20 | private ImageView status_image = null;
21 |
22 | public ConnectorStatusIndicator(Context context) {
23 | super(context);
24 |
25 | this.setUpView();
26 | }
27 |
28 | public ConnectorStatusIndicator(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 |
31 | this.setUpView();
32 | }
33 |
34 | public void setConnector(Connector connector_parameters) {
35 | if(this.connector_parameters != null)
36 | this.connector_parameters.deleteObserver(this);
37 |
38 | this.connector_parameters = connector_parameters;
39 |
40 | this.connector_parameters.addObserver(this);
41 | }
42 |
43 | private void setUpView() {
44 | this.animation = (AnimationDrawable)getResources().getDrawable(R.drawable.ic_stat_connecting);
45 |
46 | this.status_image = new ImageView(this.getContext());
47 | this.addView(this.status_image);
48 |
49 | this.setGravity(Gravity.CENTER_VERTICAL);
50 | }
51 |
52 | @Override
53 | public void update(Observable observable, Object data) {
54 | Connector connector_parameters = (Connector)observable;
55 |
56 | switch(connector_parameters.getStatus()) {
57 | case ACTIVE:
58 | this.status_image.setImageDrawable(getResources().getDrawable(R.drawable.ic_stat_active));
59 | break;
60 |
61 | case CONNECTING:
62 | this.status_image.setImageDrawable(this.animation);
63 |
64 | this.status_image.post(new Runnable() {
65 |
66 | @Override
67 | public void run() {
68 | if(animation.isRunning())
69 | animation.stop();
70 |
71 | animation.start();
72 | }
73 |
74 | });
75 | break;
76 |
77 | case OFFLINE:
78 | this.status_image.setImageDrawable(getResources().getDrawable(R.drawable.ic_stat_offline));
79 | break;
80 |
81 | case ONLINE:
82 | this.status_image.setImageDrawable(getResources().getDrawable(R.drawable.ic_stat_online));
83 | break;
84 |
85 | case UNKNOWN:
86 | this.status_image.setImageDrawable(getResources().getDrawable(R.drawable.ic_stat_unknown));
87 | break;
88 |
89 | case UPDATING:
90 | this.status_image.setImageDrawable(getResources().getDrawable(R.drawable.ic_stat_unknown));
91 | break;
92 | }
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/views/EndpointListRowView.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.views;
2 |
3 | import java.util.Observable;
4 | import java.util.Observer;
5 |
6 | import com.WithSecure.dz.EndpointAdapter;
7 | import com.WithSecure.dz.R;
8 | import com.WithSecure.jsolar.api.connectors.Endpoint;
9 |
10 | import android.content.Context;
11 | import android.util.AttributeSet;
12 | import android.view.View;
13 | import android.widget.CompoundButton;
14 | import android.widget.LinearLayout;
15 | import android.widget.RelativeLayout;
16 | import android.widget.TextView;
17 | import android.widget.ToggleButton;
18 |
19 | public class EndpointListRowView extends LinearLayout implements Observer, CompoundButton.OnCheckedChangeListener, View.OnClickListener {
20 |
21 | private Endpoint endpoint = null;
22 | private TextView endpoint_connection_string_field = null;
23 | private RelativeLayout endpoint_detail_layout = null;
24 | private TextView endpoint_name_field = null;
25 | private ConnectorStatusIndicator endpoint_status_indicator = null;
26 | private ToggleButton endpoint_toggle_button = null;
27 |
28 | private EndpointAdapter.OnEndpointSelectListener endpoint_listener = null;
29 |
30 | private volatile boolean setting_endpoint = false;
31 |
32 | public EndpointListRowView(Context context) {
33 | super(context);
34 |
35 | this.setUpView();
36 | }
37 |
38 | public EndpointListRowView(Context context, AttributeSet attrs) {
39 | super(context, attrs);
40 |
41 | this.setUpView();
42 | }
43 |
44 | public void setEndpoint(Endpoint endpoint) {
45 | if(this.endpoint != null)
46 | this.endpoint.deleteObserver(this);
47 |
48 | this.setting_endpoint = true;
49 | this.endpoint = endpoint;
50 |
51 | this.endpoint_connection_string_field.setText(this.endpoint.toConnectionString());
52 | this.endpoint_name_field.setText(this.endpoint.getName());
53 | this.endpoint_status_indicator.setConnector(this.endpoint);
54 | this.endpoint_toggle_button.setChecked(this.endpoint.isEnabled());
55 | this.setting_endpoint = false;
56 |
57 | this.endpoint.addObserver(this);
58 | }
59 |
60 | public void setEndpointListener(EndpointAdapter.OnEndpointSelectListener endpoint_listener) {
61 | this.endpoint_listener = endpoint_listener;
62 | }
63 |
64 | private void setUpView() {
65 | this.addView(View.inflate(this.getContext(), R.layout.list_view_row_endpoint, null));
66 |
67 | this.endpoint_connection_string_field = (TextView)this.findViewById(R.id.endpoint_connection_string);
68 | this.endpoint_detail_layout = (RelativeLayout)this.findViewById(R.id.list_view_row_endpoint);
69 | this.endpoint_name_field = (TextView)this.findViewById(R.id.endpoint_name);
70 | this.endpoint_status_indicator = (ConnectorStatusIndicator)this.findViewById(R.id.endpoint_status_indicator);
71 | this.endpoint_toggle_button = (ToggleButton)this.findViewById(R.id.endpoint_toggle);
72 |
73 | this.endpoint_detail_layout.setOnClickListener(this);
74 | this.endpoint_toggle_button.setOnCheckedChangeListener(this);
75 | }
76 |
77 | @Override
78 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
79 | if(!this.setting_endpoint && this.endpoint_listener != null)
80 | this.endpoint_listener.onEndpointToggle(this.endpoint, isChecked);
81 | }
82 |
83 | @Override
84 | public void onClick(View v) {
85 | if(this.endpoint_listener != null)
86 | this.endpoint_listener.onEndpointSelect(this.endpoint);
87 | }
88 |
89 | @Override
90 | public void update(Observable observable, Object data) {
91 | this.setEndpoint((Endpoint)observable);
92 | }
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/views/EndpointListView.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.views;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.ListView;
6 |
7 | public class EndpointListView extends ListView {
8 |
9 | public EndpointListView(Context context, AttributeSet attrs) {
10 | super(context, attrs);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/views/ServerListRowView.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.views;
2 |
3 | import java.util.Observable;
4 | import java.util.Observer;
5 |
6 | import android.content.Context;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 | import android.widget.CompoundButton.OnCheckedChangeListener;
10 | import android.widget.CompoundButton;
11 | import android.widget.LinearLayout;
12 | import android.widget.TextView;
13 | import android.widget.ToggleButton;
14 |
15 | import com.WithSecure.dz.R;
16 | import com.WithSecure.jsolar.api.connectors.Server;
17 | import com.WithSecure.jsolar.api.connectors.Server.OnChangeListener;
18 |
19 | public class ServerListRowView extends LinearLayout implements Observer, OnCheckedChangeListener {
20 |
21 | public interface OnServerViewListener {
22 |
23 | public void onToggle(boolean toggle);
24 |
25 | }
26 |
27 | private TextView adb_server_port_field = null;
28 | private ConnectorStatusIndicator adb_server_status_indicator = null;
29 | private ToggleButton adb_server_toggle_button = null;
30 | private Server server_parameters = null;
31 |
32 | private OnServerViewListener server_view_listener;
33 |
34 | private volatile boolean setting_server = false;
35 |
36 | public ServerListRowView(Context context) {
37 | super(context);
38 |
39 | this.initView();
40 | }
41 |
42 | public ServerListRowView(Context context, AttributeSet attrs) {
43 | super(context, attrs);
44 |
45 | this.initView();
46 | }
47 |
48 | private void initView() {
49 | this.addView(View.inflate(this.getContext(), R.layout.list_view_row_server, null));
50 |
51 | this.setBackgroundResource(android.R.drawable.list_selector_background);
52 |
53 | this.adb_server_port_field = (TextView)this.findViewById(R.id.adb_server_port);
54 | this.adb_server_status_indicator = (ConnectorStatusIndicator)this.findViewById(R.id.adb_server_status_indicator);
55 | this.adb_server_toggle_button = (ToggleButton)this.findViewById(R.id.adb_server_toggle);
56 |
57 | this.adb_server_toggle_button.setOnCheckedChangeListener(this);
58 | }
59 |
60 | @Override
61 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
62 | if(!this.setting_server)
63 | this.server_view_listener.onToggle(isChecked);
64 | }
65 |
66 | public void setServerParameters(Server server_parameters) {
67 | this.setting_server = true;
68 | this.server_parameters = server_parameters;
69 |
70 | this.adb_server_port_field.setText(Integer.valueOf(this.server_parameters.getPort()).toString());
71 | this.adb_server_status_indicator.setConnector(this.server_parameters);
72 | this.adb_server_toggle_button.setChecked(this.server_parameters.isEnabled());
73 | this.setting_server = false;
74 |
75 | this.server_parameters.setOnChangeListener(new OnChangeListener() {
76 |
77 | @Override
78 | public void onChange(Server parameters) {
79 | ServerListRowView.this.setServerParameters(parameters);
80 | }
81 |
82 | });
83 | this.server_parameters.addObserver(this);
84 | }
85 |
86 | public void setServerViewListener(OnServerViewListener listener) {
87 | this.server_view_listener = listener;
88 | }
89 |
90 | @Override
91 | public void update(Observable observable, Object data) {
92 | this.setServerParameters((Server)observable);
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/views/logger/LogMessageAdapter.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.views.logger;
2 |
3 | import com.WithSecure.jsolar.logger.LogMessage;
4 | import com.WithSecure.jsolar.logger.Logger;
5 | import com.WithSecure.jsolar.logger.OnLogMessageListener;
6 |
7 | import android.content.Context;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.widget.BaseAdapter;
11 |
12 | public class LogMessageAdapter extends BaseAdapter implements OnLogMessageListener {
13 |
14 | private Context context = null;
15 | private Logger logger = null;
16 |
17 | public LogMessageAdapter(Context context, Logger logger) {
18 | this.context = context;
19 | this.logger = logger;
20 |
21 | this.logger.addOnLogMessageListener(this);
22 | }
23 |
24 | @Override
25 | public int getCount() {
26 | return this.logger.getLogMessages().size();
27 | }
28 |
29 | @Override
30 | public Object getItem(int pos) {
31 | return this.logger.getLogMessages().get(pos);
32 | }
33 |
34 | @Override
35 | public long getItemId(int pos) {
36 | return pos;
37 | }
38 |
39 | @Override
40 | public View getView(int pos, View copyView, ViewGroup parent) {
41 | LogMessageRowView view = new LogMessageRowView(this.context);
42 |
43 | view.setLogMessage((LogMessage)this.getItem(pos));
44 |
45 | return view;
46 | }
47 |
48 | @Override
49 | public void onLogMessage(Logger logger, LogMessage message) {
50 | this.notifyDataSetChanged();
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/agent/src/main/java/com/WithSecure/dz/views/logger/LogMessageRowView.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.dz.views.logger;
2 |
3 | import com.WithSecure.dz.R;
4 | import com.WithSecure.jsolar.logger.LogMessage;
5 |
6 | import android.content.Context;
7 | import android.util.AttributeSet;
8 | import android.view.View;
9 | import android.widget.LinearLayout;
10 | import android.widget.TextView;
11 |
12 | public class LogMessageRowView extends LinearLayout {
13 |
14 | private LogMessage message = null;
15 | private TextView message_label = null;
16 | private TextView message_message = null;
17 |
18 | public LogMessageRowView(Context context) {
19 | super(context);
20 |
21 | this.setUpView();
22 | }
23 |
24 | public LogMessageRowView(Context context, AttributeSet attrs) {
25 | super(context, attrs);
26 |
27 | this.setUpView();
28 | }
29 |
30 | private void setLevel(int level) {
31 | switch(level) {
32 | case LogMessage.ASSERT:
33 | this.message_label.setText(R.string.log_level_tag_assert);
34 | this.message_label.setBackgroundColor(0xffff0000);
35 | this.message_label.setTextColor(0xffffffff);
36 | break;
37 |
38 | case LogMessage.DEBUG:
39 | this.message_label.setText(R.string.log_level_tag_debug);
40 | this.message_label.setBackgroundColor(0xff00ff00);
41 | this.message_label.setTextColor(0xff000000);
42 | break;
43 |
44 | case LogMessage.ERROR:
45 | this.message_label.setText(R.string.log_level_tag_error);
46 | this.message_label.setBackgroundColor(0xffff0000);
47 | this.message_label.setTextColor(0xffffffff);
48 | break;
49 |
50 | case LogMessage.INFO:
51 | this.message_label.setText(R.string.log_level_tag_info);
52 | break;
53 |
54 | case LogMessage.VERBOSE:
55 | this.message_label.setText(R.string.log_level_tag_verbose);
56 | this.message_label.setBackgroundColor(0xff00ff00);
57 | this.message_label.setTextColor(0xff000000);
58 | break;
59 |
60 | case LogMessage.WARN:
61 | this.message_label.setText(R.string.log_level_tag_warn);
62 | this.message_label.setBackgroundColor(0xffffa500);
63 | this.message_label.setTextColor(0xff000000);
64 | break;
65 |
66 | default:
67 | this.message_label.setText(R.string.log_level_tag_unknown);
68 | break;
69 | }
70 | }
71 |
72 | public void setLogMessage(LogMessage message) {
73 | this.message = message;
74 |
75 | this.setLevel(this.message.getLevel());
76 | this.message_message.setText(this.message.getMessage());
77 | }
78 |
79 | private void setUpView() {
80 | this.addView(View.inflate(this.getContext(), R.layout.list_view_row_log_message, null));
81 |
82 | this.message_label = (TextView)this.findViewById(R.id.log_message_level);
83 | this.message_message = (TextView)this.findViewById(R.id.log_message_message);
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/drozer.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/drozer.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_action_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_action_delete.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_action_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_action_edit.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_action_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_action_new.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_action_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_action_online.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_action_search.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_action_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_action_unknown.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_input_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_input_add.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_notification.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_stat_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_stat_active.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_stat_offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_stat_offline.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_stat_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_stat_online.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-hdpi/ic_stat_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-hdpi/ic_stat_unknown.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_action_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_action_delete.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_action_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_action_edit.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_action_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_action_new.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_action_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_action_online.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_action_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_action_unknown.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_input_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_input_add.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_stat_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_stat_active.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_stat_offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_stat_offline.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_stat_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_stat_online.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-ldpi/ic_stat_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-ldpi/ic_stat_unknown.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_action_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_action_delete.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_action_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_action_edit.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_action_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_action_new.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_action_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_action_online.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_action_search.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_action_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_action_unknown.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_input_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_input_add.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_notification.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_stat_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_stat_active.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_stat_offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_stat_offline.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_stat_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_stat_online.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-mdpi/ic_stat_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-mdpi/ic_stat_unknown.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_action_delete.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_action_delete.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_action_edit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_action_edit.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_action_new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_action_new.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_action_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_action_online.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_action_refresh.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_action_refresh.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_action_search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_action_search.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_action_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_action_unknown.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_input_add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_input_add.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_notification.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_notification.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_stat_active.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_stat_active.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_stat_offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_stat_offline.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_stat_online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_stat_online.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable-xhdpi/ic_stat_unknown.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/drawable-xhdpi/ic_stat_unknown.png
--------------------------------------------------------------------------------
/agent/src/main/res/drawable/ic_stat_connecting.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout-land/activity_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
16 |
17 |
23 |
24 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout-v14/toggle_endpoint.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout-v14/toggle_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
20 |
21 |
30 |
31 |
41 |
42 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/activity_endpoint.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
18 |
19 |
20 |
21 |
31 |
38 |
45 |
52 |
59 |
66 |
67 |
77 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/activity_endpoint_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
5 |
6 |
16 |
17 |
24 |
25 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/activity_server.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
17 |
18 |
19 |
20 |
30 |
37 |
44 |
51 |
58 |
65 |
66 |
76 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/check_list_item.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
18 |
19 |
20 |
21 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/list_view_row_endpoint.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
25 |
33 |
34 |
42 |
43 |
44 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/list_view_row_log_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/list_view_row_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
19 |
27 |
28 |
36 |
37 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/notification_session.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
16 |
17 |
23 |
31 |
32 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/toggle_endpoint.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/agent/src/main/res/layout/toggle_server.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/agent/src/main/res/menu/activity_connector.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
--------------------------------------------------------------------------------
/agent/src/main/res/menu/activity_endpoint_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/agent/src/main/res/menu/activity_main.xml:
--------------------------------------------------------------------------------
1 |
16 |
--------------------------------------------------------------------------------
/agent/src/main/res/raw/agent.bks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/raw/agent.bks
--------------------------------------------------------------------------------
/agent/src/main/res/raw/ca.bks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/agent/src/main/res/raw/ca.bks
--------------------------------------------------------------------------------
/agent/src/main/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/agent/src/main/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/agent/src/main/res/values/attrs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/agent/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/agent/src/main/res/xml/endpoint_headers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/agent/src/main/res/xml/preferences.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
12 |
13 |
14 |
17 |
23 |
28 |
33 |
39 |
45 |
51 |
52 |
55 |
56 |
59 |
63 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/androidlib/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/androidlib/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | android {
4 | namespace 'com.WithSecure.androidlib'
5 | compileSdkVersion 33
6 |
7 | defaultConfig {
8 | minSdkVersion 17
9 | targetSdkVersion 33
10 | }
11 |
12 | buildTypes {
13 | release {
14 | minifyEnabled false
15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
16 | jniDebuggable true
17 | }
18 | debug {
19 | jniDebuggable true
20 | minifyEnabled false
21 | }
22 | }
23 | }
24 |
25 | dependencies {
26 | }
27 |
--------------------------------------------------------------------------------
/androidlib/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
--------------------------------------------------------------------------------
/androidlib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
--------------------------------------------------------------------------------
/androidlib/src/main/java/com/WithSecure/androidlib/android/app/NotifyingService.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.androidlib.android.app;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationManager;
5 | import android.app.PendingIntent;
6 | import android.app.Service;
7 | import android.content.Context;
8 | import android.widget.RemoteViews;
9 |
10 | public abstract class NotifyingService extends Service {
11 |
12 | private NotificationManager notification_manager = null;
13 |
14 | protected void hideNotification(String tag, int view_id) {
15 | this.notification_manager.cancel(tag, view_id);
16 | }
17 |
18 | @Override
19 | public void onCreate() {
20 | this.notification_manager = (NotificationManager)this.getSystemService(Context.NOTIFICATION_SERVICE);
21 | }
22 |
23 | protected void onCreateNotification(RemoteViews view) {}
24 |
25 | protected void showNotification(String tag, int view_id, int icon_id, PendingIntent intent) {
26 | Notification notification = new Notification();
27 |
28 | RemoteViews contentView = new RemoteViews(this.getPackageName(), view_id);
29 |
30 | this.onCreateNotification(contentView);
31 |
32 | notification.icon = icon_id;
33 | notification.flags = Notification.FLAG_ONGOING_EVENT;
34 | notification.contentIntent = intent;
35 | notification.contentView = contentView;
36 |
37 | this.notification_manager.notify(tag, view_id, notification);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/androidlib/src/main/res/layout/list_view_row_log_message.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
20 |
21 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/androidlib/src/main/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/androidlib/src/main/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/androidlib/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/androidlib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | MWR Common Android
4 |
5 | A
6 | D
7 | E
8 | I
9 | U
10 | V
11 | W
12 |
13 |
14 |
--------------------------------------------------------------------------------
/androidlib/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | id 'com.android.application' version '8.0.1' apply false
4 | id 'com.android.library' version '8.0.1' apply false
5 | id 'org.jetbrains.kotlin.android' version '1.7.20' apply false
6 |
7 | // Custom
8 | id 'com.google.protobuf' version '0.9.1' apply false
9 | }
--------------------------------------------------------------------------------
/docs/Overview.md:
--------------------------------------------------------------------------------
1 | # Code Overview
2 |
3 | The Drozer Agent is composed of 4 modules.
4 |
5 | 1. Agent - Main android app, has intents, activities, receivers etc...
6 | 2. JSolar - Formerly JDiesel, android library in charge of handling all protobuf communication between the Drozer python client and the Drozer Agent
7 | 3. tlslib - Direct copy of mwrtls, android library providing the trust stores as well as X509certificate finger/thumbprint calculations
8 | 4. androidlib - Android Library providing an easy wrapper for showing notifications
9 |
10 | The main functionality of the agent is in the Agent and JSolar modules. and as such those will be documented here.
11 |
12 | ## Agent
13 |
14 | see agent.md
15 |
16 | ## JSolar
17 |
18 | see Jsolar.md
19 |
20 |
21 | # Building
22 |
23 | Building the project should be as simple as cloning the project via android studio, and then pressing the build button.
24 | If you have any issues what so ever feel free to reach out to me on slack @William Ben Embarek
25 |
26 | Next steps for the agent:
27 | Code comments
28 | Gitlab runners for building
29 | Proper code linting
30 | Cleaning of Ken's yayxyay methods and comments in the codebase
--------------------------------------------------------------------------------
/docs/agent.md:
--------------------------------------------------------------------------------
1 | # Agent
2 |
3 | This document is still a WIP
4 | The agent is the android app itself which runs on the device. The agent is in charge of making the various calls to the jsolar library to begin with.
5 |
6 | ## Activities
7 |
8 | These are just android activities... Quick check doesnt look like they implement any "functionality", just providing the screens
9 |
10 | **StartBroadcastActivity** appears to be some mess made by Ken before he left, who just pushes "yayintentyay" to master???
11 | This might have been for testing? unsure at least, will probably be safe to delete before we go public with a new version
12 |
13 | ## Helpers
14 |
15 | **IntentProxyToContentProvider**: Code is actually documented, this feels however it should have just been implemented as a drozer module and not as an activity?
16 | Again some more Ken messy code.
17 |
18 | ## Models
19 |
20 | **EndpointManager**: Appears to provide main logic for managing android Interprocess Communication Endpoints, and more specifically for saving them in the internal SQL DB.
21 |
22 | **ServerSettings**: Simple preference editor / getter
23 |
24 | ## Providers
25 |
26 | **Provider**: Good question as to what this does, seems to be another Ken feature
27 |
28 | ## Receivers
29 |
30 | **StartMainActivityReceiver**:
31 |
32 | **StartServiceReceiver**:
33 |
34 | ## Service Connectors
35 |
36 | ## Services
37 |
38 | ## Views
39 |
40 |
--------------------------------------------------------------------------------
/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 | android.enableJetifier=true
19 | # Kotlin code style for this project: "official" or "obsolete":
20 | kotlin.code.style=official
21 | # Enables namespacing of each library's R class so that its R class includes only the
22 | # resources declared in the library itself and none from the library's dependencies,
23 | # thereby reducing the size of the R class for that library
24 | android.nonTransitiveRClass=true
25 | android.defaults.buildfeatures.buildconfig=true
26 | android.nonFinalResIds=false
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ReversecLabs/drozer-agent/a730ac85bc68f0f3c3f938b975dbcc2880f8052e/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Oct 28 20:58:33 CST 2023
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/jsolar/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.4.1)
2 |
3 | add_library( mstring
4 | SHARED
5 | src/main/cpp/libmstring/mstring.cpp)
6 |
7 | target_link_libraries(mstring
8 | android
9 | log)
--------------------------------------------------------------------------------
/jsolar/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.library'
3 | id 'com.google.protobuf'
4 | }
5 |
6 | android {
7 | namespace 'com.WithSecure.jsolar'
8 | compileSdk 33
9 |
10 | defaultConfig {
11 | minSdk 17
12 | targetSdk 33
13 | }
14 |
15 | buildTypes {
16 | release {
17 | minifyEnabled false
18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
19 | jniDebuggable true
20 | }
21 | debug {
22 | jniDebuggable true
23 | minifyEnabled false
24 | }
25 | }
26 | externalNativeBuild {
27 | cmake {
28 | path 'CMakeLists.txt'
29 | }
30 | }
31 |
32 | // Configuration for protobuf generation
33 | sourceSets {
34 | main {
35 | java {
36 | srcDirs += 'build/generated/source/proto/main/java'
37 | }
38 | proto {
39 | srcDir 'src/main/proto'
40 | }
41 | }
42 | }
43 |
44 | // Build protobuf
45 | protobuf {
46 | protoc {
47 | artifact = 'com.google.protobuf:protoc:3.21.10'
48 | }
49 | generateProtoTasks{
50 | all().each { task ->
51 | task.builtins{
52 | java {
53 | }
54 | }
55 | }
56 | }
57 | }
58 | }
59 |
60 | dependencies {
61 |
62 | implementation project(':tlslib')
63 | implementation 'com.google.protobuf:protobuf-java:3.21.10'
64 | implementation 'com.google.protobuf:protobuf-java-util:3.21.10'
65 | implementation 'androidx.core:core-ktx:1.9.0'
66 | }
--------------------------------------------------------------------------------
/jsolar/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
--------------------------------------------------------------------------------
/jsolar/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
13 |
14 |
--------------------------------------------------------------------------------
/jsolar/src/main/cpp/libmstring/mstring.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * mstring.cpp
3 | * Buffered String Search.
4 | *
5 | * Written by Rodrigo Chiossi
6 | *
7 | *
8 | * This is a native implementation of a buffered string search algorithm,
9 | * optimized to reduce the overhead of the JNI call.
10 | *
11 | * The number of strings found is usually very big which makes it impossible
12 | * return a list of jstrings objects back to java (due to the restriction of
13 | * 512 local references) without paying the price of DeleteLocalRef().
14 | *
15 | * This implementation creates a single Java string with all strings separated
16 | * by a new line. An actual list can be then retrieved in Java using
17 | * split("\n"), or any method alike.
18 | *
19 | * The chunk size was obtained by profiling the execution time over several
20 | * classes.dex extracted from apks. The best observed value was 16k.
21 | */
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 |
29 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR , "mercury-native", __VA_ARGS__)
30 |
31 | #ifdef __cplusplus
32 | extern "C" {
33 | #endif
34 |
35 | #define CHUNK_SIZE 16348
36 | #define LIST_START_SIZE 4096
37 |
38 | #define MAX_STR_SIZE 4096
39 | #define MIN_STR_SIZE 4
40 |
41 | char read_buffer[CHUNK_SIZE];
42 | unsigned bytes_in_buffer;
43 | unsigned read_ptr;
44 | unsigned eof;
45 |
46 | char* string_list = NULL;
47 |
48 | /*
49 | * Function: Read a new chunk from the target file
50 | * Parameters: file - open file descriptor to the target
51 | */
52 | void reset_buffer(FILE* file) {
53 | bytes_in_buffer = fread(read_buffer,1,CHUNK_SIZE,file);
54 | read_ptr = 0;
55 | eof = 0;
56 | }
57 |
58 | /*
59 | * Function: Read a byte from the file buffer
60 | * Parameters: file - open file descriptor to the target
61 | * Return: Byte read
62 | */
63 | char read_char(FILE* file) {
64 | if (bytes_in_buffer != CHUNK_SIZE && read_ptr >= bytes_in_buffer) {
65 | eof = 1;
66 | return 0xff;
67 | }
68 |
69 | if (read_ptr == CHUNK_SIZE) {
70 | reset_buffer(file);
71 | }
72 |
73 | return read_buffer[read_ptr++];
74 | }
75 |
76 | /*
77 | * Function: Extract Strings from file
78 | * Parameters: path - taget file
79 | * Return: Number of uris found
80 | */
81 | int strings_file(const char* path) {
82 | FILE* file = fopen(path,"r");
83 |
84 | unsigned max_size = LIST_START_SIZE;
85 | unsigned cur_size = 0;
86 |
87 | char buffer[MAX_STR_SIZE];
88 | char* next_str;
89 | unsigned char c_byte;
90 | unsigned length;
91 |
92 | unsigned num_strings = 0;
93 |
94 | if (file == NULL) {
95 | LOGE("Error opening file : %s",path);
96 | return -1;
97 | }
98 |
99 | string_list = (char*) malloc(sizeof(char)*max_size);
100 |
101 | reset_buffer(file);
102 |
103 | c_byte = read_char(file);
104 | length = 0;
105 | while (!eof) {
106 | /* check if character is printable */
107 | while (0x20 <= c_byte && c_byte <= 0x7E && length < MAX_STR_SIZE - 1 && !eof) {
108 | buffer[length++] = c_byte;
109 | c_byte = read_char(file);
110 | }
111 |
112 | if (length >= MIN_STR_SIZE) {
113 | /* grow string list buffer if needed */
114 | if (cur_size+length >= max_size) {
115 | string_list = (char*) realloc(string_list, sizeof(char)*max_size*2);
116 | if (string_list == NULL) {
117 | LOGE("Error: Failed to allocate memory!");
118 | return -1;
119 | }
120 | max_size *= 2;
121 | }
122 |
123 | next_str = &string_list[cur_size];
124 | strncpy(next_str,buffer,length);
125 | next_str[length] = '\n';
126 |
127 | cur_size+=length+1;
128 |
129 | num_strings++;
130 | }
131 |
132 | /* start a new string */
133 | length = 0;
134 |
135 | c_byte = read_char(file);
136 | }
137 |
138 | string_list[cur_size] = '\0';
139 |
140 | fclose(file);
141 |
142 | return num_strings;
143 | }
144 |
145 | /*
146 | * Class: com_mwr_droidhg_util_Strings
147 | * Method: strings
148 | * Signature: (Ljava/lang/String;)[Ljava/lang/String;
149 | */
150 | JNIEXPORT jstring JNICALL Java_com_WithSecure_jsolar_util_Strings_get
151 | (JNIEnv *env, jclass obj, jstring jpath)
152 | {
153 | const char *path = env->GetStringUTFChars(jpath, 0);
154 | int num;
155 |
156 | /* Get string list */
157 | num = strings_file(path);
158 |
159 | if (num <= 0) return NULL;
160 |
161 | /* Convert to a Java String */
162 | env->ReleaseStringUTFChars(jpath, path);
163 | jstring ret = env->NewStringUTF(string_list);
164 |
165 | free(string_list);
166 |
167 | return ret;
168 | }
169 |
170 | #ifdef __cplusplus
171 | }
172 | #endif
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/APIVersionException.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api;
2 |
3 | public class APIVersionException extends Exception{
4 |
5 | // Why tf do we have this magic string, who tf knows
6 | private static final long serialVersionUID = 6223917687313162316L;
7 |
8 | public APIVersionException(String message) {
9 | super(message);
10 | }
11 |
12 | }
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/DeviceInfo.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api;
2 |
3 | public class DeviceInfo {
4 |
5 | private String android_id;
6 | private String manufacturer;
7 | private String model;
8 | private String software;
9 |
10 | public DeviceInfo(String android_id, String manufacturer, String model, String software) {
11 | this.android_id = android_id;
12 | this.manufacturer = manufacturer;
13 | this.model = model;
14 | this.software = software;
15 | }
16 |
17 | public String getAndroid_id() {
18 | return android_id;
19 | }
20 |
21 | public String getManufacturer() {
22 | return manufacturer;
23 | }
24 |
25 | public String getModel() {
26 | return model;
27 | }
28 |
29 | public String getSoftware() {
30 | return software;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/Frame.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api;
2 |
3 |
4 | import java.io.IOException;
5 | import java.io.InputStream;
6 | import java.nio.ByteBuffer;
7 | import com.WithSecure.jsolar.api.Protobuf.Message;
8 |
9 | public class Frame {
10 |
11 | private static final int SIZE_SIZE = 4; //Bytes
12 | private static final int VERSION_SIZE = 4; //Bytes
13 | private static final int HEADER_SIZE = VERSION_SIZE + SIZE_SIZE;
14 |
15 | private static final int VERSION = 2;
16 |
17 | private int version;
18 | private Message payload;
19 | private int size;
20 |
21 | public Frame(Message payload) {
22 | this.version = VERSION;
23 | this.setPayload(payload);
24 | }
25 |
26 | public Frame(int version, Message payload) {
27 | this.version = version;
28 | this.setPayload(payload);
29 | }
30 |
31 | public int getVersion() {
32 | return version;
33 | }
34 |
35 | public Message getPayload() {
36 | return payload;
37 | }
38 |
39 | public int getSize() {
40 | return size;
41 | }
42 |
43 | public static Frame readFrom(InputStream in) throws IOException, APIVersionException {
44 | byte[] bytes = new byte[HEADER_SIZE];
45 | int length = in.read(bytes);
46 |
47 | if(length == -1)
48 | throw new IOException("invalid input stream");
49 | else if (length != HEADER_SIZE)
50 | return null;
51 |
52 | ByteBuffer buf = ByteBuffer.wrap(bytes);
53 |
54 | int version = buf.getInt();
55 | int size = buf.getInt();
56 |
57 | if (version != VERSION)
58 | throw new APIVersionException("Expected version " + VERSION + ", got " + version);
59 |
60 | byte[] message = new byte[size];
61 | int bytes_read = 0;
62 | while (bytes_read < size)
63 | bytes_read += in.read(message, bytes_read, size-bytes_read);
64 |
65 | return new Frame(version, Message.parseFrom(message));
66 | }
67 |
68 | private void setPayload(Message payload) {
69 | this.payload = payload;
70 | this.size = payload.toByteArray().length;
71 | }
72 |
73 | public byte[] toByteArray() {
74 | byte[] bytes = new byte[HEADER_SIZE + this.getSize()];
75 |
76 | ByteBuffer buf = ByteBuffer.wrap(bytes);
77 |
78 | buf.putInt(this.getVersion());
79 | buf.putInt(this.getSize());
80 | buf.put(this.payload.toByteArray());
81 |
82 | return bytes;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/InvalidMessageException.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api;
2 |
3 | import com.WithSecure.jsolar.api.Protobuf.Message;
4 |
5 | import java.util.Locale;
6 |
7 | public class InvalidMessageException extends RuntimeException{
8 |
9 | private Message invalid_message = null;
10 | // I dont even know...
11 | private static final long serialVersionUID = -3727783632022708351L;
12 |
13 | public InvalidMessageException(Message invalid_message) {
14 | this.invalid_message = invalid_message;
15 | }
16 |
17 | public Message getInvalid_message() {return this.invalid_message;}
18 | public String toString() {
19 | return String.format(Locale.ENGLISH, "Invalid message: %s", this.invalid_message.toString());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/UnexpectedMessageException.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api;
2 |
3 | import java.util.Locale;
4 | import com.WithSecure.jsolar.api.Protobuf.Message.MessageType;
5 |
6 | public class UnexpectedMessageException extends RuntimeException {
7 |
8 | private static final long serialVersionUID = 2323712339351270587L;
9 |
10 | private MessageType type;
11 |
12 | public UnexpectedMessageException(MessageType type) {
13 | this.type = type;
14 | }
15 |
16 | public String toString() {
17 | return String.format(Locale.ENGLISH, "Unexpected MessageType: %d", this.type.getNumber());
18 | }
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/builders/MessageFactory.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.builders;
2 |
3 | import com.WithSecure.jsolar.api.Protobuf.Message;
4 | import com.WithSecure.jsolar.api.Protobuf.Message.*;
5 |
6 | public class MessageFactory {
7 |
8 | Message.Builder builder = null;
9 |
10 | public MessageFactory(ReflectionRequest reflectionRequest) {
11 | this.builder = Message.newBuilder();
12 |
13 | this.builder.setType(Message.MessageType.REFLECTION_REQUEST);
14 | this.builder.setReflectionRequest(reflectionRequest);
15 | }
16 |
17 | public MessageFactory(ReflectionResponse reflectionResponse) {
18 | this.builder = Message.newBuilder();
19 |
20 | this.builder.setType(Message.MessageType.REFLECTION_RESPONSE);
21 | this.builder.setReflectionResponse(reflectionResponse);
22 | }
23 |
24 | public MessageFactory(ReflectionResponseFactory responseFactory) {
25 | this(responseFactory.build());
26 | }
27 |
28 | public MessageFactory(SystemRequest systemRequest) {
29 | this.builder = Message.newBuilder();
30 |
31 | this.builder.setType(MessageType.SYSTEM_REQUEST);
32 | this.builder.setSystemRequest(systemRequest);
33 | }
34 |
35 | public MessageFactory(SystemRequestFactory requestFactory) {
36 | this(requestFactory.build());
37 | }
38 |
39 | public MessageFactory(SystemResponse system_response) {
40 | this.builder = Message.newBuilder();
41 |
42 | this.builder.setType(Message.MessageType.SYSTEM_RESPONSE);
43 | this.builder.setSystemResponse(system_response);
44 | }
45 |
46 | public MessageFactory(SystemResponseFactory system_response) {
47 | this(system_response.build());
48 | }
49 |
50 |
51 | public Message build() {
52 | return this.builder.build();
53 | }
54 |
55 | public MessageFactory inReplyTo(Message message) {
56 | this.builder.setId(message.getId());
57 | return this;
58 | }
59 |
60 | public MessageFactory setId(int id) {
61 | this.builder.setId(id);
62 | return this;
63 | }
64 |
65 | }
66 |
67 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/builders/SystemRequestFactory.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.builders;
2 |
3 | import com.WithSecure.jsolar.api.Protobuf.Message;
4 | import com.WithSecure.jsolar.api.Protobuf.Message.*;
5 |
6 | public class SystemRequestFactory {
7 |
8 | private Message.SystemRequest.Builder builder = null;
9 |
10 | public static SystemRequestFactory bind() {
11 | return new SystemRequestFactory(Message.SystemRequest.RequestType.BIND_DEVICE);
12 | }
13 |
14 | public static SystemRequestFactory unbind() {
15 | return new SystemRequestFactory(SystemRequest.RequestType.UNBIND_DEVICE);
16 | }
17 |
18 | private SystemRequestFactory(SystemRequest.RequestType type) {
19 | this.builder = SystemRequest.newBuilder().setType(type);
20 | }
21 |
22 | public SystemRequest build() {
23 | return this.builder.build();
24 | }
25 |
26 | public SystemRequestFactory setDevice(String device_id, String manufacturer, String model, String software) {
27 | this.builder.setDevice(Message.Device.newBuilder()
28 | .setId(device_id)
29 | .setManufacturer(manufacturer)
30 | .setModel(model)
31 | .setSoftware(software));
32 |
33 | return this;
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/builders/SystemResponseFactory.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.builders;
2 |
3 | import com.WithSecure.jsolar.api.Protobuf.Message;
4 | import com.WithSecure.jsolar.api.Protobuf.Message.*;
5 |
6 | public class SystemResponseFactory {
7 |
8 | private Message.SystemResponse.Builder builder = null;
9 |
10 | public static SystemResponseFactory deviceList(Message request) {
11 | return new SystemResponseFactory(SystemResponse.ResponseType.DEVICE_LIST, SystemResponse.ResponseStatus.SUCCESS);
12 | }
13 |
14 | public static SystemResponseFactory pong(Message ping) {
15 | return new SystemResponseFactory(SystemResponse.ResponseType.PONG, SystemResponse.ResponseStatus.SUCCESS);
16 | }
17 |
18 | public static SystemResponseFactory session(String session_id) {
19 | return new SystemResponseFactory(SystemResponse.ResponseType.SESSION_ID, SystemResponse.ResponseStatus.SUCCESS).setSessionId(session_id);
20 | }
21 |
22 | private SystemResponseFactory(SystemResponse.ResponseType type, SystemResponse.ResponseStatus status) {
23 | this.builder = SystemResponse.newBuilder().setType(type).setStatus(status);
24 | }
25 |
26 | public SystemResponseFactory addDevice(String device_id, String manufacturer, String model, String software) {
27 | this.builder.addDevices(Message.Device.newBuilder()
28 | .setId(device_id)
29 | .setManufacturer(manufacturer)
30 | .setModel(model)
31 | .setSoftware(software));
32 |
33 | return this;
34 | }
35 |
36 | public SystemResponse build() {
37 | return this.builder.build();
38 | }
39 |
40 | public SystemResponseFactory isError() {
41 | this.builder.setStatus(SystemResponse.ResponseStatus.ERROR);
42 |
43 | return this;
44 | }
45 |
46 | public SystemResponseFactory isSuccess() {
47 | this.builder.setStatus(SystemResponse.ResponseStatus.SUCCESS);
48 |
49 | return this;
50 | }
51 |
52 | public static SystemResponseFactory sessionList(Message request) {
53 | return new SystemResponseFactory(SystemResponse.ResponseType.SESSION_LIST, SystemResponse.ResponseStatus.SUCCESS);//addDevice();
54 | }
55 |
56 | public SystemResponseFactory setSessionId(String session_id) {
57 | this.builder.setSessionId(session_id);
58 |
59 | return this;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/connectors/Connector.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.connectors;
2 |
3 | import com.WithSecure.jsolar.logger.Logger;
4 |
5 | import java.util.Observable;
6 |
7 | // Default constructor in java.util.observable is depreciated
8 | public abstract class Connector extends Observable {
9 |
10 | public static final String CONNECTOR_CONNECTED = "connector:connected";
11 | public static final String CONNECTOR_ENABLED = "connector:enabled";
12 | public static final String CONNECTOR_LOG_MESSAGE = "connector:logmessage";
13 | public static final String CONNECTOR_OPEN_SESSIONS = "connector:opensessions";
14 | public static final String CONNECTOR_SSL_FINGERPRINT = "certificate:fingerprint";
15 |
16 | public enum Status { ACTIVE, CONNECTING, UNKNOWN, UPDATING, ONLINE, OFFLINE };
17 |
18 | public volatile boolean enabled = false;
19 | public volatile Status status = Status.UNKNOWN;
20 |
21 | private Logger logger = new Logger(this);
22 |
23 | public synchronized boolean isEnabled() {
24 | return this.enabled;
25 | }
26 |
27 | public Logger getLogger() {
28 | return this.logger;
29 | }
30 |
31 | public synchronized Status getStatus() {
32 | return this.status;
33 | }
34 |
35 | public synchronized void setStatus(Status status) {
36 | if(this.status != status) {
37 | this.status = status;
38 |
39 | this.setChanged();
40 | this.notifyObservers();
41 | }
42 | }
43 |
44 | public abstract boolean verifyPassword(String password);
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/connectors/EndpointSocketFactory.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.connectors;
2 |
3 | import java.io.IOException;
4 | import java.net.InetAddress;
5 | import java.net.Socket;
6 | import java.security.KeyManagementException;
7 | import java.security.NoSuchAlgorithmException;
8 | import java.security.SecureRandom;
9 |
10 | import javax.net.ssl.KeyManager;
11 | import javax.net.ssl.SSLContext;
12 | import javax.net.ssl.SSLSocketFactory;
13 | import javax.net.ssl.TrustManager;
14 |
15 | /**
16 | * The EndpointSocketFactory builds Socket objects from a given Endpoint.
17 | *
18 | * If the given Endpoint has SSL enabled, an SSLSocket will be returned that has
19 | * been initialised with the Endpoint's TrustManager.
20 | */
21 | public class EndpointSocketFactory {
22 |
23 | public Socket createSocket(Endpoint endpoint) throws IOException, KeyManagementException {
24 | if(endpoint.isSSL())
25 | return this.createSSLSocket(endpoint.toInetAddress(), endpoint.getPort(), endpoint.getTrustManager());
26 | else
27 | return this.createSocket(endpoint.toInetAddress(), endpoint.getPort());
28 | }
29 |
30 | public Socket createSocket(InetAddress host, int port) throws IOException {
31 | return new Socket(host, port);
32 | }
33 |
34 | public Socket createSSLSocket(InetAddress host, int port, TrustManager trust_manager) throws IOException, KeyManagementException {
35 | try {
36 | SSLContext context = SSLContext.getInstance("TLS");
37 | context.init(new KeyManager[0], new TrustManager[] { trust_manager }, new SecureRandom());
38 |
39 | return ((SSLSocketFactory)context.getSocketFactory()).createSocket(host, port);
40 | }
41 | catch(NoSuchAlgorithmException e) {
42 | throw new RuntimeException("no such algorithm TLS");
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/connectors/Server.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.connectors;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 |
6 | import java.io.FileInputStream;
7 | import java.io.FileNotFoundException;
8 | import java.io.IOException;
9 | import java.security.KeyStore;
10 | import java.security.KeyStoreException;
11 | import java.security.NoSuchAlgorithmException;
12 | import java.security.UnrecoverableKeyException;
13 | import java.security.cert.CertificateException;
14 |
15 | import javax.net.ssl.KeyManager;
16 | import javax.net.ssl.KeyManagerFactory;
17 |
18 | public class Server extends Connector{
19 |
20 | public static final String SERVER_KEY_PASSWORD = "server:key:password";
21 | public static final String SERVER_KEYSTORE_PASSWORD = "server:ks:password";
22 | public static final String SERVER_KEYSTORE_PATH = "server:ks:path";
23 | public static final String SERVER_PASSWORD = "server:password";
24 | public static final String SERVER_PORT = "server:port";
25 | public static final String SERVER_SSL = "server:ssl";
26 |
27 | public interface OnChangeListener {
28 | public void onChange(Server parameters);
29 | }
30 |
31 | public interface OnDetailedStatusListener {
32 | public void onDetailedStatus(Bundle status);
33 | }
34 |
35 | private KeyManager[] keyManagers = null;
36 | private char[] keyPassword = null;
37 | private String keyStorePath = null;
38 | private char[] keyStorePassword = null;
39 | private OnChangeListener onChangeListener = null;
40 | private String password = null;
41 | private int port = 31415;
42 | private boolean ssl = false;
43 |
44 | private OnDetailedStatusListener onDetailedStatusListener;
45 |
46 | public Server() {}
47 |
48 | //TODO Implement functionality for this
49 | public Server(int port) {
50 | this.setPort(port);
51 | }
52 |
53 | public KeyManager[] getKeyManagers() throws CertificateException, FileNotFoundException, IOException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
54 | if (this.keyManagers == null) {
55 | KeyStore keyStore = KeyStore.getInstance("BKS");
56 | keyStore.load(new FileInputStream(this.keyStorePath), this.keyStorePassword);
57 |
58 | KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
59 | keyManagerFactory.init(keyStore, this.keyPassword);
60 | }
61 |
62 | return this.keyManagers;
63 | }
64 |
65 | public String getPassword() {
66 | return password;
67 | }
68 |
69 | public int getPort() {
70 | return port;
71 | }
72 |
73 | public boolean hasPassword() {
74 | return this.password != null && this.password != "";
75 | }
76 |
77 | public boolean isSSL() {
78 | return this.ssl;
79 | }
80 |
81 | public void resetKeyManagerFactory() {
82 | this.keyManagers = null;
83 | }
84 |
85 | public void setDetailedStatus(Bundle status) {
86 | if(this.onDetailedStatusListener != null) {
87 | this.onDetailedStatusListener.onDetailedStatus(status);
88 | }
89 | }
90 |
91 | public void setKeyPassword(char [] password) {
92 | this.keyPassword = password;
93 | }
94 |
95 | public void setKeyStorePath(String keyStorePath) {
96 | this.keyStorePath = keyStorePath;
97 | }
98 |
99 | public void setKeyStorePassword(char[] keyStorePassword) {
100 | this.keyStorePassword = keyStorePassword;
101 | }
102 |
103 | public void setOnChangeListener(OnChangeListener onChangeListener) {
104 | this.onChangeListener = onChangeListener;
105 | }
106 |
107 | public void setPassword(String password) {
108 | this.password = password;
109 | }
110 |
111 | public void setOnDetailedStatusListener(OnDetailedStatusListener onDetailedStatusListener) {
112 | this.onDetailedStatusListener = onDetailedStatusListener;
113 | }
114 |
115 | public void setPort(int port) {
116 | this.port = port;
117 | }
118 |
119 | public void setSSL(boolean ssl) {
120 | this.ssl = ssl;
121 | }
122 |
123 | //Allows for blank passwords
124 | @Override
125 | public boolean verifyPassword(String password) {
126 | Log.i("ServerPassword","Guessed password was : " + password + " Actual password is: " + this.getPassword());
127 | return this.getPassword() == null && (password == null || password.equals("")) || password.equals(this.getPassword());
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/connectors/ServerSocketFactory.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.connectors;
2 |
3 | import java.io.IOException;
4 | import java.net.ServerSocket;
5 | import java.security.KeyManagementException;
6 | import java.security.KeyStoreException;
7 | import java.security.NoSuchAlgorithmException;
8 | import java.security.UnrecoverableKeyException;
9 | import java.security.cert.CertificateException;
10 |
11 | import javax.net.ssl.SSLContext;
12 | import javax.net.ssl.SSLServerSocket;
13 |
14 | public class ServerSocketFactory {
15 | public ServerSocket createSocket(Server server) throws CertificateException, IOException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
16 | if (server.isSSL())
17 | return this.createSSLSocket(server);
18 | else
19 | return new ServerSocket(server.getPort());
20 | }
21 |
22 | public SSLServerSocket createSSLSocket(Server server) throws CertificateException, IOException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
23 | try {
24 | SSLContext context = SSLContext.getInstance("TLS");
25 | context.init(server.getKeyManagers(), null, null);
26 |
27 | return (SSLServerSocket) context.getServerSocketFactory().createServerSocket(server.getPort());
28 | } catch (NoSuchAlgorithmException e) {
29 | throw new RuntimeException("no such algorithm TLS");
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/handlers/MessageHandler.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.handlers;
2 |
3 | import com.WithSecure.jsolar.api.InvalidMessageException;
4 | import com.WithSecure.jsolar.api.Protobuf;
5 |
6 | public interface MessageHandler {
7 | public Protobuf.Message handle(Protobuf.Message message) throws InvalidMessageException;
8 | }
9 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/links/Client.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.links;
2 |
3 | import com.WithSecure.jsolar.api.DeviceInfo;
4 | import com.WithSecure.jsolar.api.connectors.Connector;
5 | import com.WithSecure.jsolar.api.connectors.Endpoint;
6 | import com.WithSecure.jsolar.api.connectors.EndpointSocketFactory;
7 | import com.WithSecure.jsolar.api.transport.SocketTransport;
8 | import com.WithSecure.jsolar.connection.SecureConnection;
9 | import com.WithSecure.jsolar.logger.LogMessage;
10 |
11 | import java.io.IOException;
12 | import java.net.Socket;
13 | import java.net.UnknownHostException;
14 | import java.security.KeyManagementException;
15 |
16 | public class Client extends Link{
17 |
18 | public static final int RESET_TIMEOUT = 5000;
19 |
20 | public Client(Endpoint endpoint, DeviceInfo deviceInfo) {
21 | super(endpoint, deviceInfo);
22 | }
23 |
24 | public String getHostCertificateFingerprint() {
25 | return ((SecureConnection) this.connection).getHostCertificateFingerprint();
26 | }
27 |
28 | public String getPeerCertificateFingerprint() {
29 | return ((SecureConnection) this.connection).getPeerCertificateFingerprint();
30 | }
31 |
32 | @Override
33 | public void resetConnection() {
34 | this.parameters.setStatus(Endpoint.Status.CONNECTING);
35 |
36 | try {
37 | Thread.sleep(RESET_TIMEOUT);
38 | } catch (InterruptedException e) {
39 | this.log(LogMessage.DEBUG, "Issue resetting client connection");
40 | }
41 |
42 | super.resetConnection();
43 | }
44 |
45 | @Override
46 | public void run() {
47 | Endpoint endpoint = (Endpoint) this.parameters;
48 |
49 | this.log(LogMessage.INFO, "Starting...");
50 | this.running = true;
51 |
52 | while (this.running) {
53 | try {
54 | if (this.connection == null) {
55 | this.parameters.setStatus(Endpoint.Status.CONNECTING);
56 |
57 | this.log(LogMessage.INFO, "Attempting connection to " + endpoint.toConnectionString() + "...");
58 | Socket socket = new EndpointSocketFactory().createSocket(endpoint);
59 |
60 | if (socket != null) {
61 | this.log(LogMessage.INFO, "Socket connected.");
62 |
63 | this.log(LogMessage.INFO, "Attempting to start drozer thread...");
64 | this.createConnection(new SocketTransport(socket));
65 | }
66 | } else {
67 | synchronized (this.connection) {
68 | try {
69 | this.connection.wait();
70 | } catch (InterruptedException e) {
71 | this.log(LogMessage.DEBUG, "Issue waiting on thread in client : " + e.getMessage());
72 | } catch (IllegalMonitorStateException e) {
73 | this.log(LogMessage.DEBUG, "Issue waiting on thread in client : " + e.getMessage());
74 | }
75 | }
76 |
77 | if (this.connection.started && !this.connection.running) {
78 | this.log(LogMessage.INFO, "Connection was reset.");
79 |
80 | this.resetConnection();
81 | }
82 | }
83 | } catch (UnknownHostException e) {
84 | this.log(LogMessage.ERROR, "Unknown Host: " + endpoint.getHost());
85 |
86 | this.stopConnector();
87 | }
88 | catch(IOException e) {
89 | this.log(LogMessage.ERROR, "IO Error. Resetting connection.");
90 | this.log(LogMessage.DEBUG, e.getMessage());
91 |
92 | this.resetConnection();
93 | }
94 | catch(KeyManagementException e) {
95 | this.log(LogMessage.ERROR, "Error loading key material for SSL.");
96 |
97 | this.stopConnector();
98 | }
99 | }
100 | this.log(LogMessage.INFO, "Stopped.");
101 | }
102 |
103 | @Override
104 | public void setStatus(Connector.Status status) {
105 | this.parameters.setStatus(status);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/links/Link.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.links;
2 |
3 | import android.util.Log;
4 |
5 | import com.WithSecure.jsolar.api.DeviceInfo;
6 | import com.WithSecure.jsolar.api.connectors.Connection;
7 | import com.WithSecure.jsolar.api.connectors.Connector;
8 | import com.WithSecure.jsolar.api.sessions.Session;
9 | import com.WithSecure.jsolar.api.sessions.SessionCollection;
10 | import com.WithSecure.jsolar.api.transport.Transport;
11 | import com.WithSecure.jsolar.connection.AbstractLink;
12 | import com.WithSecure.jsolar.logger.LogMessage;
13 | import com.WithSecure.jsolar.logger.Logger;
14 |
15 | public abstract class Link extends AbstractLink {
16 |
17 | protected Connector parameters = null;
18 | private DeviceInfo device_info;
19 |
20 | private Logger logger = null;
21 |
22 | public Link(Connector parameters, DeviceInfo device_info) {
23 | this.parameters = parameters;
24 | this.device_info = device_info;
25 |
26 | this.setSessionCollection(new SessionCollection(this));
27 | }
28 |
29 | public abstract void setStatus(Connector.Status status);
30 |
31 | @Override
32 | protected void createConnection(Transport transport) {
33 | if(transport.isLive()) {
34 | this.connection = new Connection(this, this.device_info, transport);
35 | this.connection.start();
36 | }
37 | }
38 |
39 | @Override
40 | public Session getSession(String session_id) {
41 | return (Session)super.getSession(session_id);
42 | }
43 |
44 | public void log(int level, String message) {
45 | if(this.logger != null)
46 | this.logger.log(level, message);
47 | else
48 | Log.i("link", message);
49 | }
50 |
51 | public void log(LogMessage message) {
52 | if(this.logger != null)
53 | this.logger.log(message);
54 | else
55 | Log.i("link", message.getMessage());
56 | }
57 |
58 | public void setLogger(Logger logger) {
59 | this.logger = logger;
60 | }
61 |
62 | public Session startSession(String password) {
63 | Log.i("Link","Got password: " + password);
64 | Boolean verifyPass = this.parameters.verifyPassword(password);
65 | Log.i("Link","Password match: " + verifyPass);
66 | if(verifyPass)
67 | return (Session)this.createSession();
68 | else
69 | return null;
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/sessions/Session.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.sessions;
2 |
3 | import android.os.Looper;
4 |
5 | import com.WithSecure.jsolar.api.InvalidMessageException;
6 | import com.WithSecure.jsolar.api.Protobuf;
7 | import com.WithSecure.jsolar.api.handlers.MessageHandler;
8 | import com.WithSecure.jsolar.api.handlers.ReflectionMessageHandler;
9 | import com.WithSecure.jsolar.api.links.Link;
10 | import com.WithSecure.jsolar.connection.AbstractSession;
11 | import com.WithSecure.jsolar.reflection.ObjectStore;
12 |
13 | public class Session extends AbstractSession {
14 |
15 | private Link connector = null;
16 | public ObjectStore object_store = new ObjectStore();
17 | private MessageHandler reflection_message_handler = new ReflectionMessageHandler(this);
18 |
19 | public Session(Link connector) {
20 | super();
21 |
22 | this.connector = connector;
23 | }
24 |
25 | protected Session(String session_id) {
26 | super(session_id);
27 | }
28 |
29 | public static Session nullSession() {
30 | return new Session("null");
31 | }
32 |
33 | @Override
34 | protected Protobuf.Message handleMessage(Protobuf.Message message) throws InvalidMessageException {
35 | return this.reflection_message_handler.handle(message);
36 | }
37 |
38 | @Override
39 | public void run(){
40 | Looper.prepare();
41 |
42 | super.run();
43 | }
44 |
45 | @Override
46 | public void send(Protobuf.Message message) {
47 | this.connector.send(message);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/sessions/SessionCollection.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.sessions;
2 |
3 | import com.WithSecure.jsolar.api.connectors.Connector;
4 | import com.WithSecure.jsolar.api.links.Link;
5 | import com.WithSecure.jsolar.connection.AbstractSession;
6 | import com.WithSecure.jsolar.connection.AbstractSessionCollection;
7 |
8 | public class SessionCollection extends AbstractSessionCollection {
9 |
10 | private Link connector = null;
11 | // private SessionServiceConnection session_service_connection = null;
12 |
13 | public SessionCollection(Link connector) {
14 | this.connector = connector;
15 | // this.session_service_connection = new SessionServiceConnection();
16 |
17 | // SessionService.startAndBindToService(Agent.getInstance().getMercuryContext(), this.session_service_connection);
18 | }
19 |
20 | @Override
21 | public Session create() {
22 | return (Session)this.storeSession(new Session(this.connector));
23 | }
24 |
25 | // public SessionServiceConnection getSessionService() {
26 | // return this.session_service_connection;
27 | // }
28 |
29 | @Override
30 | public void onSessionStarted(AbstractSession session) {
31 | this.connector.setStatus(Connector.Status.ACTIVE);
32 |
33 | // this.getSessionService().notifySessionStarted(session.getSessionId());
34 | }
35 |
36 | @Override
37 | public void onSessionStopped(AbstractSession session) {
38 | // this.getSessionService().notifySessionStopped(session.getSessionId());
39 | this.connector.setStatus(Connector.Status.ONLINE);
40 |
41 | if(!this.any())
42 | this.connector.lastSessionStopped();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/transport/SecureTransport.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.transport;
2 |
3 | public interface SecureTransport {
4 |
5 | public abstract String getHostCertificateFingerprint();
6 | public abstract String getPeerCertificateFingerprint();
7 | }
8 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/transport/SocketTransport.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.transport;
2 |
3 | import com.WithSecure.common.tls.X509Fingerprint;
4 |
5 |
6 | import android.util.Log;
7 |
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.io.OutputStream;
11 | import java.net.Socket;
12 | import java.security.cert.X509Certificate;
13 |
14 | import javax.net.ssl.SSLPeerUnverifiedException;
15 | import javax.net.ssl.SSLSession;
16 | import javax.net.ssl.SSLSocket;
17 |
18 | public class SocketTransport extends Transport implements SecureTransport {
19 |
20 | private static final int SO_TIMEOUT = 5000; // Milliseconds
21 |
22 | private InputStream in = null;
23 | private OutputStream out = null;
24 | private Socket socket = null;
25 |
26 | public SocketTransport(Socket socket) {
27 | try {
28 | this.socket = socket;
29 | this.socket.setSoTimeout(SO_TIMEOUT);
30 |
31 | this.in = socket.getInputStream();
32 | this.out = socket.getOutputStream();
33 | } catch (IOException e) {
34 | Log.e("SocketConnection", "IOException when grabbing streams: " + e.getMessage());
35 | }
36 | }
37 |
38 | @Override
39 | public String getHostCertificateFingerprint() {
40 | SSLSession session = ((SSLSocket) this.socket).getSession();
41 | return new X509Fingerprint((X509Certificate) session.getLocalCertificates()[0]).toString();
42 | }
43 |
44 | @Override
45 | // This was rewritten to remove dependency on com.mwr.common.tls
46 | // By introducing our OWN dependency...
47 | // This is mostly due to Java removing features and never replacing them
48 | public String getPeerCertificateFingerprint() {
49 | try {
50 | SSLSession session = ((SSLSocket) this.socket).getSession();
51 | X509Certificate peerCertificate = (X509Certificate) session.getPeerCertificates()[0];
52 | return new X509Fingerprint(peerCertificate).toString();
53 | } catch (SSLPeerUnverifiedException e) {
54 | return "No valid peer certificate";
55 | }
56 | }
57 |
58 | @Override
59 | public void close() {
60 | try {
61 | this.in.close();
62 | this.out.close();
63 | this.socket.close();
64 | } catch (IOException e) {
65 | Log.e("SocketConnection", "IOException when closing socket: " + e.getMessage());
66 | }
67 | }
68 |
69 | @Override
70 | protected InputStream getInputStream() throws IOException {
71 | return this.in;
72 | }
73 |
74 | @Override
75 | protected OutputStream getOutputStream() throws IOException {
76 | return this.out;
77 | }
78 |
79 | @Override
80 | public boolean isLive() {
81 | return !this.socket.isClosed();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/transport/Transport.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.transport;
2 |
3 | import com.WithSecure.jsolar.api.APIVersionException;
4 | import com.WithSecure.jsolar.api.Frame;
5 |
6 | import android.util.Log;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.io.OutputStream;
10 |
11 | public abstract class Transport {
12 |
13 | public abstract void close();
14 | protected abstract InputStream getInputStream() throws IOException;
15 | protected abstract OutputStream getOutputStream() throws IOException;
16 | public abstract boolean isLive();
17 |
18 | public Frame receive() throws APIVersionException, IOException, TransportDisconnectedException {
19 | if(this.getInputStream() != null)
20 | return Frame.readFrom(this.getInputStream());
21 | else
22 | throw new TransportDisconnectedException();
23 | }
24 |
25 | public void send(Frame frame) throws IOException {
26 | Log.i("TransportLog","Sending frame " + frame.getPayload().toString());
27 | this.getOutputStream().write(frame.toByteArray());
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/api/transport/TransportDisconnectedException.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.api.transport;
2 |
3 | public class TransportDisconnectedException extends Exception {
4 | //Wtf
5 | private static final long serialVersionUID = -8654251407371633543L;
6 | }
7 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/connection/AbstractLink.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.connection;
2 |
3 | import com.WithSecure.jsolar.api.Protobuf.Message;
4 | import com.WithSecure.jsolar.api.transport.Transport;
5 |
6 | public abstract class AbstractLink extends Thread {
7 |
8 | public volatile boolean running = false;
9 | protected volatile AbstractConnection connection = null;
10 | private AbstractSessionCollection sessions;
11 |
12 | public boolean checkForLiveness() { return true; }
13 |
14 | protected abstract void createConnection(Transport transport);
15 |
16 | protected AbstractSession createSession() {
17 | return this.sessions.create();
18 | }
19 |
20 | public boolean dieWithLastSession() { return false; }
21 | public boolean mustBind() { return true; }
22 |
23 | public AbstractSession getSession(String session_id) {
24 | return this.sessions.get(session_id);
25 | }
26 |
27 | public boolean hasSessions() {
28 | return this.sessions.any();
29 | }
30 |
31 | public void lastSessionStopped() {
32 | if(this.dieWithLastSession())
33 | this.stopConnection();
34 | }
35 |
36 | public void send(Message message) {
37 | this.connection.send(message);
38 | }
39 |
40 | public AbstractSession startSession() {
41 | return this.startSession(null);
42 | }
43 |
44 | public abstract AbstractSession startSession(String password);
45 |
46 | public void resetConnection() {
47 | this.connection = null;
48 | }
49 |
50 | protected void setSessionCollection(AbstractSessionCollection sessions) {
51 | this.sessions = sessions;
52 | }
53 |
54 | protected void stopConnection() {
55 | if(this.connection != null)
56 | this.connection.stopConnection();
57 | }
58 |
59 | public void stopConnector() {
60 | this.running = false;
61 |
62 | this.stopConnection();
63 | }
64 |
65 | public AbstractSession stopSession(String session_id) {
66 | return (AbstractSession)this.sessions.stop(session_id);
67 | }
68 |
69 | public void stopSessions() {
70 | this.sessions.stopAll();
71 | }
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/connection/AbstractSession.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.connection;
2 |
3 | import com.WithSecure.jsolar.api.InvalidMessageException;
4 | import com.WithSecure.jsolar.api.Protobuf.Message;
5 |
6 | import java.math.BigInteger;
7 | import java.security.SecureRandom;
8 | import java.util.HashSet;
9 | import java.util.Set;
10 | import java.util.concurrent.BlockingQueue;
11 | import java.util.concurrent.LinkedBlockingQueue;
12 |
13 | public abstract class AbstractSession extends Thread{
14 |
15 | public interface OnSessionStatusListener {
16 | public void onSessionStarted(AbstractSession session);
17 | public void onSessionStopped(AbstractSession session);
18 | }
19 |
20 | private BlockingQueue messages = new LinkedBlockingQueue();
21 | private String session_id = null;
22 | public volatile boolean running = false;
23 |
24 | private Set on_session_status_listeners = new HashSet();
25 |
26 | public AbstractSession() {
27 | this.session_id = this.generateSessionId();
28 | }
29 |
30 | protected AbstractSession(String session_id) {
31 | this.session_id = session_id;
32 | }
33 |
34 | public void addOnSessionStatusListener(OnSessionStatusListener listener) {
35 | this.on_session_status_listeners.add(listener);
36 | }
37 |
38 | public void deliverMessage(Message message) {
39 | this.messages.offer(message);
40 | }
41 |
42 | private String generateSessionId() {
43 | return new BigInteger(130, new SecureRandom()).toString(32);
44 | }
45 |
46 | public String getSessionId() {
47 | return session_id;
48 | }
49 |
50 | protected abstract Message handleMessage(Message message) throws InvalidMessageException;
51 |
52 | public void removeOnSessionStatusListener(OnSessionStatusListener listener) {
53 | this.on_session_status_listeners.remove(listener);
54 | }
55 |
56 | @Override
57 | public void run() {
58 | this.running = true;
59 | for(OnSessionStatusListener l : this.on_session_status_listeners)
60 | l.onSessionStarted(this);
61 |
62 | while(this.running) {
63 | Message message = null;
64 |
65 | try {
66 | message = this.messages.take();
67 | } catch (InterruptedException e) {
68 | //Lol we do nothing. good job whoever wrote the original code
69 | }
70 |
71 | if(message != null) {
72 | try {
73 | Message response = this.handleMessage(message);
74 |
75 | if(response != null)
76 | this.send(response);
77 | } catch (InvalidMessageException e) {
78 | // Once again failing and ignoring
79 | }
80 | }
81 | }
82 |
83 | for(OnSessionStatusListener l : this.on_session_status_listeners)
84 | l.onSessionStopped(this);
85 | }
86 |
87 | public abstract void send(Message message);
88 |
89 | public void stopSession() {
90 | this.running = false;
91 | this.interrupt();
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/connection/AbstractSessionCollection.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.connection;
2 |
3 | import java.util.Collection;
4 | import java.util.HashMap;
5 |
6 | public abstract class AbstractSessionCollection implements AbstractSession.OnSessionStatusListener {
7 |
8 | private HashMap sessions = new HashMap();
9 |
10 | public Collection all() {
11 | return this.sessions.values();
12 | }
13 |
14 | public boolean any() {
15 | return !this.sessions.isEmpty();
16 | }
17 |
18 | public abstract AbstractSession create();
19 |
20 | protected AbstractSession storeSession(AbstractSession session) {
21 | this.sessions.put(session.getSessionId(), session);
22 | session.addOnSessionStatusListener(this);
23 | session.start();
24 |
25 | return session;
26 | }
27 |
28 | public AbstractSession get(String session_id) {
29 | return this.sessions.get(session_id);
30 | }
31 |
32 | // Todo fix error handling
33 | public AbstractSession stop(String session_id) {
34 | AbstractSession session = this.sessions.get(session_id);
35 | if(session != null) {
36 | this.sessions.remove(session_id);
37 |
38 | try {
39 | session.stopSession();
40 | session.join();
41 | } catch (InterruptedException e) {
42 | e.printStackTrace();
43 | }
44 | }
45 | return session;
46 | }
47 |
48 | public void stopAll() {
49 | String[] keys = this.sessions.keySet().toArray(new String[] {});
50 | for (String session_id : keys) {
51 | this.stop(session_id);
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/connection/SecureConnection.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.connection;
2 |
3 | public interface SecureConnection {
4 |
5 | public String getHostCertificateFingerprint();
6 | public String getPeerCertificateFingerprint();
7 |
8 | }
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/logger/LogMessage.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.logger;
2 |
3 | import android.os.Bundle;
4 | import android.util.Log;
5 |
6 | public class LogMessage {
7 |
8 | public static final String LEVEL = "log:level";
9 | public static final String MESSAGE = "log:message";
10 |
11 | public static final int VERBOSE = 0x00000002;
12 | public static final int DEBUG = 0x00000003;
13 | public static final int INFO = 0x00000004;
14 | public static final int WARN = 0x00000005;
15 | public static final int ERROR = 0x00000006;
16 | public static final int ASSERT = 0x00000007;
17 |
18 | private int level;
19 | private String message;
20 |
21 |
22 | public LogMessage(String message) {
23 | this(LogMessage.INFO, message);
24 | }
25 |
26 | public LogMessage(int level, String message) {
27 | this.level = level;
28 | this.message = message;
29 | }
30 |
31 | public LogMessage(Bundle bundle) {
32 | this(bundle.getInt(LogMessage.LEVEL), bundle.getString(LogMessage.MESSAGE));
33 | }
34 |
35 | public int getLevel() {
36 | return level;
37 | }
38 |
39 | public String getMessage() {
40 | return this.message != null ? this.message : "No message.";
41 | }
42 |
43 | public Bundle toBundle() {
44 | Bundle bundle = new Bundle();
45 |
46 | bundle.putInt(LogMessage.LEVEL, this.getLevel());
47 | bundle.putString(LogMessage.MESSAGE, this.getMessage());
48 |
49 | return bundle;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/logger/Logger.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.logger;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashSet;
5 | import java.util.List;
6 | import java.util.Set;
7 |
8 |
9 | // Custom logger class copied from jdiesel, why it's custom I dont know but will update here if I figure it out
10 | // ideally this just gets replaced with log4j or some other mature logging solution
11 | public class Logger {
12 |
13 | private List log_messages = new ArrayList<>();
14 | private Set> on_log_message_listeners = new HashSet>();
15 | private T owner;
16 |
17 | public Logger(T owner) { this.owner = owner;}
18 |
19 | public void addOnLogMessageListener(OnLogMessageListener listener) {
20 | this.on_log_message_listeners.add(listener);
21 | }
22 |
23 | public List getLogMessages() { return this.log_messages; }
24 |
25 | public T getOwner() { return this.owner; }
26 |
27 | public void log(int level, String message) {this.log(new LogMessage(level, message));}
28 |
29 | public void log(LogMessage message) {
30 | this.log_messages.add(message);
31 |
32 | for(OnLogMessageListener listener : this.on_log_message_listeners) {
33 | listener.onLogMessage(this,message);
34 | }
35 | }
36 |
37 | public void removeOnLogMessageListener(OnLogMessageListener listener) {
38 | this.on_log_message_listeners.remove(listener);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/logger/OnLogMessageListener.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.logger;
2 |
3 | public interface OnLogMessageListener {
4 | public void onLogMessage(Logger tLogger, LogMessage message);
5 | }
6 |
--------------------------------------------------------------------------------
/jsolar/src/main/java/com/WithSecure/jsolar/reflection/ObjectStore.java:
--------------------------------------------------------------------------------
1 | package com.WithSecure.jsolar.reflection;
2 |
3 | import android.util.SparseArray;
4 |
5 | import java.util.List;
6 |
7 | public class ObjectStore {
8 |
9 | private SparseArray