Skip to content

Instantly share code, notes, and snippets.

@leonjza
Last active March 2, 2020 07:58
Show Gist options
  • Save leonjza/7fcc137f7f798ffca00ddf2bfef36b63 to your computer and use it in GitHub Desktop.
Save leonjza/7fcc137f7f798ffca00ddf2bfef36b63 to your computer and use it in GitHub Desktop.
objection Stetho sideload plugin
import os
import click
from objection.utils.plugin import Plugin
from objection.commands.filemanager import _path_exists_android, _upload_android
from objection.commands.device import _get_android_environment
from objection.state.connection import state_connection
class StethoLoader(Plugin):
""" StethoLoader loads Facebook's stetho """
def __init__(self, ns):
"""
Creates a new instance of the plugin
:param ns:
"""
implementation = {
'meta': 'Work with Facebook\'s stetho',
'commands': {
'load': {
'meta': 'Load stetho',
'exec': self.load_stetho
}
}
}
super().__init__(__file__, ns, implementation)
self.inject()
self.stetho_jar = 'stetho.apk'
def load_stetho(self, args: list):
"""
Loads stetho.
:param args:
:return:
"""
agent = state_connection.get_api()
device_jar_path = os.path.join(agent.env_android_paths()['cacheDirectory'], self.stetho_jar)
if not _path_exists_android(device_jar_path):
print('Stetho not uploaded, uploading...')
if not self._upload_stetho(device_jar_path):
return
click.secho('Asking stetho to load...', dim=True)
self.api.init_stetho()
def _upload_stetho(self, location: str) -> bool:
"""
Uploads Stetho to the remote filesystem.
:return:
"""
local_stetho = os.path.join(os.path.abspath(os.path.dirname(__file__)), self.stetho_jar)
if not os.path.exists(local_stetho):
click.secho('{0} not available next to plugin file. Please download Stetho and convert first!'.format(self.stetho_jar), fg='red')
click.secho(' curl -sL https://github.com/facebook/stetho/releases/download/v1.5.1/stetho-1.5.1-fatjar.jar -O', dim=True)
click.secho(' dx --dex --output="stetho.apk" stetho-1.5.1.jar', dim=True)
return False
_upload_android(local_stetho, location)
return True
namespace = 'stetho'
plugin = StethoLoader
rpc.exports = {
initStetho: function () {
Java.perform(function () {
const stethoClassName = 'com.facebook.stetho.Stetho';
const stethoJar = 'stetho.apk';
const pathClassLoader = Java.use('dalvik.system.PathClassLoader');
const javaFile = Java.use('java.io.File');
const activityThread = Java.use('android.app.ActivityThread');
const currentApplication = activityThread.currentApplication();
const context = currentApplication.getApplicationContext();
// Check if stetho is here already.
console.log('Searching for stetho...');
const stethoCheck = Java.enumerateLoadedClassesSync().filter(function (e) {
return e.includes('com.facebook.stetho.Stetho');
});
if (stethoCheck.length > 0) {
console.log('Stetho class already loaded!');
} else {
console.log('Stetho class not found, running classloader');
const packageFilesDir = context.getCacheDir().getAbsolutePath().toString();
const stethoJarDir = packageFilesDir + '/' + stethoJar;
const javaStethoJarDir = javaFile.$new(stethoJarDir);
if (!javaStethoJarDir.exists()) {
console.log('Stetho jar is not available in cachedir at: ' + packageFilesDir);
console.log('Stetho NOT successfully loaded');
return;
}
// https://developer.android.com/reference/dalvik/system/PathClassLoader#PathClassLoader(java.lang.String,%20java.lang.String,%20java.lang.ClassLoader)
const loader = pathClassLoader.$new(javaStethoJarDir.getAbsolutePath(), null, currentApplication.getClassLoader());
console.log('Loading class ' + stethoClassName + ' using new classloader');
loader.loadClass(stethoClassName);
}
// Attempt to use the new class. First, search for a specific classloader to use.
try {
console.log('Searching for the new stetho classloader...');
const classLoaders = Java.enumerateClassLoadersSync().filter(function (l) {
return l.toString().includes('stetho');
});
if (classLoaders.length != 1) { throw "No valid Stetho classloader found"; }
Java.classFactory.loader = classLoaders[0];
console.log('Using the class: ' + stethoClassName);
const stetho = Java.use(stethoClassName);
console.log('Calling initializeWithDefaults');
stetho.initializeWithDefaults(context);
} catch (err) {
console.log('Failed to load by specifying the classloader with: ' + err.toString());
console.log('Trying plan B...');
try {
const stetho = Java.use(stethoClassName);
console.log('Calling initializeWithDefaults');
stetho.initializeWithDefaults(context);
} catch (err) {
console.log('Could not find stetho without specifying a classloader either (plan B). Err: ' + err.toString());
console.log('Stetho NOT successfully loaded');
return;
}
}
console.log('\nStetho up!');
});
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment