This plugin should sideload Facebook's Stetho [1], loaded as a plugin in objection[2].
[1] http://facebook.github.io/stetho/
[2] https://github.com/sensepost/objection
| 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 |
This plugin should sideload Facebook's Stetho [1], loaded as a plugin in objection[2].
[1] http://facebook.github.io/stetho/
[2] https://github.com/sensepost/objection
| 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!'); | |
| }); | |
| } | |
| } |