Skip to content

Commit

Permalink
apk: Allow gadget config file customization from CLI
Browse files Browse the repository at this point in the history
Add a -c/--gadget-config flag, valid when --gadget is also in use, that
adds arbitrary entries to the injected gadget's config file's
"interaction" section[1].

[1]: https://frida.re/docs/gadget/
  • Loading branch information
tchebb authored and oleavr committed Oct 19, 2024
1 parent 71a162d commit af32002
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
1 change: 1 addition & 0 deletions completions/frida.fish
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ complete --command frida-create --no-files --require-parameter --short-option=t
add_base_arguments frida-apk
complete --command frida-apk --force-files --short-option=o --long-option=output --description="output path"
complete --command frida-apk --force-files --short-option=g --long-option=gadget --description="inject the specified gadget library"
complete --command frida-apk --force-files --short-option=c --long-option=gadget-config --description="set the given key=value gadget interaction config"


######## frida-compile ########
Expand Down
37 changes: 34 additions & 3 deletions frida_tools/apk.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from __future__ import annotations

import argparse
import json
import os
import struct
from enum import IntEnum
from io import BufferedReader
from typing import BinaryIO, List
from typing import BinaryIO, Dict, List
from zipfile import ZipFile

GADGET_NAME = "libfridagadget.so"
Expand All @@ -14,6 +15,11 @@
LD_PRELOAD="$(dirname "$0")/{GADGET_NAME}" "$@"
"""

GADGET_INTERACTION_CONFIG = {
"type": "listen",
"on_load": "wait",
}


def main() -> None:
from frida_tools.application import ConsoleApplication
Expand All @@ -31,6 +37,22 @@ def _add_options(self, parser: argparse.ArgumentParser) -> None:
help="inject the specified gadget library",
metavar="GADGET",
)

def key_val_type(arg: str) -> tuple[str, str]:
split = arg.split("=", 1)
if len(split) == 1:
raise argparse.ArgumentTypeError("config entry must be of form key=value")
return (split[0], split[1])

parser.add_argument(
"-c",
"--gadget-config",
type=key_val_type,
action="append",
help="set the given key=value gadget interaction config",
metavar="GADGET_CONFIG",
)

parser.add_argument("apk", help="apk file")

def _needs_device(self) -> bool:
Expand All @@ -40,6 +62,10 @@ def _initialize(self, parser: argparse.ArgumentParser, options: argparse.Namespa
self._output_path = options.output
self._path = options.apk
self._gadget = options.gadget
self._gadget_config = options.gadget_config

if self._gadget_config and self._gadget is None:
parser.error("cannot configure gadget without injecting gadget")

if not self._path.endswith(".apk"):
parser.error("path must end in .apk")
Expand All @@ -53,7 +79,10 @@ def _start(self) -> None:
if self._gadget is not None:
gadget_arch = get_gadget_arch(self._gadget)
lib_dir = f"lib/{gadget_arch}/"
inject(self._gadget.name, lib_dir, self._output_path)

config = {"interaction": {**GADGET_INTERACTION_CONFIG, **dict(self._gadget_config or [])}}

inject(self._gadget.name, lib_dir, config, self._output_path)
except Exception as e:
self._update_status(f"Error: {e}")
self._exit(1)
Expand Down Expand Up @@ -114,9 +143,11 @@ def debug(path: str, output_path: str) -> None:
oz.writestr(info.filename, f.read(), info.compress_type)


def inject(gadget_so: str, lib_dir: str, output_apk: str) -> None:
def inject(gadget_so: str, lib_dir: str, config: Dict[str, Dict[str, str]], output_apk: str) -> None:
config_name = GADGET_NAME.removesuffix(".so") + ".config.so"
with ZipFile(output_apk, "a") as oz:
oz.writestr(lib_dir + "wrap.sh", WRAP_SCRIPT)
oz.writestr(lib_dir + config_name, json.dumps(config))
oz.write(gadget_so, lib_dir + GADGET_NAME)


Expand Down

0 comments on commit af32002

Please sign in to comment.