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!'); | |
}); | |
} | |
} |