Skip to content

MatrixEditor/bshark

Repository files navigation

🦈 bshark

bshark is a Python library that provides an interface to capturing and processing Android Binder transactions as well as compiling AIDL files into struct definitions.

Installation

Currently, there is no python package available for bshark. Therefore, you have to use the GIT installation candidate:

pip install bshark@git+https://github.com/MatrixEditor/bshark.git

Please follow the documentation on how to use this library.

Examples

Compiling an AIDL file:

from bshark.compiler import BaseLoader, Compiler, ParcelableDef

# More information about the Java sources are given in the
# documentation
loader = BaseLoader(['/path/to/android-java-root/'])
units  = loader.import_("android.accounts.Account")

c = Compiler(units[0], loader)
pdef: ParcelableDef = c.compile()

or using the command line interface:

python3 -m bshark.compiler         \ # base command
    -I /path/to/android-java-root/ \ # include directories
    compile                        \ # action
    -o /path/to/output/            \ # output directory
    android.accounts.Account       \ # target class to compile (AIDL file required)

Batch compilation

Batch compilation is supported in the same way in the command line interface.

python3 -m bshark.compiler        \ # base commmand
    -I $ANDROID_SRC               \ # include directories (Android source required)
    batch-compile                 \ # action
    -o $OUTPUT_DIR                \ # output directory
    [--recursive] [--force]         # options

Manual Message Parsing:

In order to parse a message, we need the compiled binder interface and all necessary parcelable definitions involved. Consider we want to decode a message from the android.app.IActivityManager with transaction code 63. First, we have to compile the binder interface:

from bshark.compiler import BaseLoader, Compiler
from bshark.parcel import parse

loader = BaseLoader(['/path/to/android-java-root/'])
(unit,) = loader.import_("android.app.IActivityManager")

# A single call to compile is enough. It will replace the
# cached unit and place the binder definition in it.
c = Compiler(unit, loader)
bdef = c.compile()

data = ...
msg = parse(
    data,           # recevied data
    63,             # transaction code
    loader,         # loader
    version=...,    # Android API version
)

The output would look something like this:

IncomingMessage(
    smp=3254779908,
    work_suid=4294967295,
    env=<Environment.SYST: 1398362964>,
    descriptor='android.app.IActivityManager',
    data={
        'connection': {
            'type': 1936206469,
            'flags': 275,
            'handle': 41,
            'cookie': 0,
            'status': 201326593
        },
        'stable': 0
    }
)

Capturing Binder transactions:

In order to receive binder transactions, we have to use a custom TransactionListener, which wil be used later on by an Agent.

from bshark.agent import TransactionListener
from bshark.parcel import parse, IncomingMessage, OutgoingMessage

loader = ... # the loader must store compiled Parcelable definitions
# e.g.
loader = BaseLoader(['/path/to/compiled-files-root/'])
loader.import_("*")

class MyListener(TransactionListener):
    def on_transaction(self, code: int, data: bytes) -> None:
        msg: IncomingMessage = parse(
            data,           # recevied data
            code,           # transaction code
            loader,         # loader
            version=...,    # Android API version
        )

    def on_reply(self, code: int, interface: str, data: bytes):
        msg: OutgoingMessage = parse(
            data,           # recevied data
            code,           # transaction code
            loader,         # loader
            version=...,    # Android API version
            descriptor=interface, # target interface
            in_=False
        )

With the listener, we can now capture transactions using an agent object:

from bshark.agent import Agent

device = ... # aquire device object from frida
agent = Agent(
    loader,
    android_version=..., # Android API version
    device=device,       # the device to use
    listener=MyListener(),
)

# either spawn an application or attach to the pid
pid = ...
agent.attach(pid)
# or
agent.spawn('com.example.app', extras=["/path/to/my-extra-script.js"])

About

🦈 Wireshark for Android Binder - capture and decode IPC messages from Android devices.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Languages