Skip to content

Advanced patterns

metall0id edited this page Nov 26, 2014 · 3 revisions

This section documents some of the more advanced usage of the module API as a series of patterns.

Added Java

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.

Colouring Output

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.

Command-line Arguments

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))

Exploit and Scanner

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."

Tab Autocompletion

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 where text starts in line; and
  • endidx: the index of where text ends in line.

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.