-
Notifications
You must be signed in to change notification settings - Fork 791
Advanced patterns
This section documents some of the more advanced usage of the module API as a series of patterns.
Problem: Client-side reflection can be slow, especially when dealing with large amounts of data.
Solution: Write a performance-sensitive routine as a snippet of Java code, and load it into the running VM.
Example: information.native
The ClassLoader can upload an apk file from your PC to the agent, and extract a specified class from it. This class can then be instantiated, and otherwise used as a reflected object.
The information.native
module, for instance, uses a Java class Native
:
class Native {
public static String[] findLibraries(ApplicationInfo app) {
...
}
}
This must be compiled into an apk file, which can be loaded into the Dalvik VM by the class loader:
def execute(self, arguments):
Native = self.loadClass("information/Native.apk", "Native")
for package in packages:
libraries = Native.libraries(package.applicationInfo)
The current version of drozer offers a Makefile with an apks
target that will build all Java sources into Android packages. A future version will automatically perform this conversion for you at runtime.
drozer will cache the apk file on the agent, for performance reasons, but automatically push an updated version should it be available.
Problem: It is hard to identify important information in a monochrome command-line interface.
Solution: drozer allows colours to be applied to output.
Drawback: Does not work on Windows.
drozer supports the use of simple tags to indicate where colour should be applied to the output:
def execute(self, arguments):
self.stdout.write("This is [color red]red[/color]!")
self.stdout.write("This is [color green]green[/color]!")
drozer supports the colours: blue; green; purple; red; and yellow.
Problem: A useful module will need to accept user input.
Solution: drozer allows command-line arguments to be defined for a module.
Example: All built-in modules.
drozer provides each module with an instance of argparse
that it can use to provide command-line options for the user.
drozer will initialise the argparse
object, and pass it to the add_arguments()
method on a module so the prepare it. drozer then uses the parser to read user input from the command-line, and passes the resultant dictionary to the execute()
method.
def add_arguments(self, parser):
parser.add_argument("-f", "--filter", default=None, help="specify a keyword to filter by")
def execute(self, arguments):
self.stdout.write("filtering by %s\n" % (arguments.filter))
Problem: A single platform may have many vulnerabilities. It would be nice to be able to demonstrate each individually, but also scan to test for their presence across the entire collection.
Solution: drozer allows a special module to be indicated as a Vulnerability
test case, so a VulnerabilityScanner
can test a group of modules at once.
Example: exploit.pilfer.oem.samsung.*
and scanner.oem.samsung
A drozer Vulnerability
is a special type of module that does not define an execute
method. It defines two methods – one to test for the presence of the vulnerability, and one to exploit it.
class MyVulnerability(Module, common.Vulnerability):
path = ["exploit", "example"]
def isVulnerable(self, arguments):
return True
def exploit(self, arguments):
self.stdout.write("Exploited!")
The isVulnerable()
method performs some check to test for the presence of a vulnerability, for instance checking the Android version, or attempting to read from a particular content uri.
The exploit()
method performs a proof-of-concept exploit, and prints some results to stdout
.
Invoking this module directly will either print the result of running the exploit, or a message indicating that the system is not vulnerable.
A VulnerabilityScanner
can be defined that collects all Vulnerability
modules from a particular namespace, and performs a vulnerable/not vulnerable check:
class MyScanner(Module, common.VulnerabilityScanner):
path = ["scanner", "example"]
vulnerabilities = "exploit.example."
drozer offers tab autocompletion for commands and module names, using the readline library. Modules are able to provide their own suggestions for tab autocompletion, by overriding the complete()
method:
class MyModule(Module):
def complete(self, text, line, begidx, endidx):
return ['array', 'of', 'suggestions']
This method will be invoked automatically by drozer, passing in:
-
text
: the string for which completion has been requested; -
line
: the entire commandline arguments entered so far; -
begidx
: the index of wheretext
starts inline
; and -
endidx
: the index of wheretext
ends inline
.
For instance, the following example provides filename completion for a module:
from drozer.modules import common, Module
class MyModule(Module)
def complete(self, text, line, begidx, endidx):
return common.path_completion.on_console(text)
A future version will update the auto-completion API to make it easier to use, and more robust. It is not recommended to implement a complete()
method in your modules.