Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
221 changes: 221 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,223 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
*$py.class

.vscode/*
.vscode
src/.vscode/*
src/.vscode

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py.cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
# Pipfile.lock

# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# uv.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
# poetry.lock
# poetry.toml

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
# pdm.lock
# pdm.toml
.pdm-python
.pdm-build/

# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
# pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# Redis
*.rdb
*.aof
*.pid

# RabbitMQ
mnesia/
rabbitmq/
rabbitmq-data/

# ActiveMQ
activemq-data/

# SageMath parsed files
*.sage.py

# Environments
.env
.envrc
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
# .idea/

# Abstra
# Abstra is an AI-powered process automation framework.
# Ignore directories containing user credentials, local state, and settings.
# Learn more at https://abstra.io/docs
.abstra/

# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/

# Ruff stuff:
.ruff_cache/

# PyPI configuration file
.pypirc

# Marimo
marimo/_static/
marimo/_lsp/
__marimo__/

# Streamlit
.streamlit/secrets.toml
.DS_Store
.gadgetCache/
51 changes: 37 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,22 +37,45 @@ An APK patcher, for use with [objection](https://github.com/sensepost/objection)
* **29th March 2020:** Added `--save-apk` parameter to save a copy of the unpatched single APK for use with other tools.
* **27th March 2020:** Initial release supporting split APKs and the `--no-enable-user-certs` flag.

## Usage ##
Install the target Android application on your device and connect it to your computer/VM so that `adb devices` can see it, then run:
## Installation & Usage ##

Installation (development)

Install the project in editable mode (recommended during development):

```
python -m pip install -e .
```

Install for production / normal use:

```
python -m pip install .
```

After installation the CLI entry point `patch-apk` will be available. Alternatively you can run directly from the source tree:

```
python -m patch_apk.main {package-name}
```

Usage

Ensure your Android device is connected and visible to adb (`adb devices`). Then run:

```
python3 patch-apk.py {package-name}
patch-apk {package-name}
```

The package-name parameter can be the fully-qualified package name of the Android app, such as `com.google.android.youtube`, or a partial package name, such as `tube`.
The `{package-name}` parameter can be a fully-qualified package name such as `com.google.android.youtube`, or a partial package name (e.g. `tube`) — the tool will attempt to resolve partial names and ask for confirmation if multiple matches are found.

Along with injecting an instrumentation gadget, the script also automatically enables support for user-installed CA certificates by injecting a network security configuration file into the APK. To disable this functionality, pass the `--no-enable-user-certs` parameter on the command line.
By default the tool will inject the Frida gadget and enable support for user-installed CA certificates by modifying the app's network security config. To disable the network cert modification, pass `--no-enable-user-certs` on the command line.

### Examples ###
**Basic usage:** Simply install the target Android app on your device, make sure `adb devices` can see your device, then pass the package name to `patch-apk.py`.
**Basic usage:** Simply install the target Android app on your device, make sure `adb devices` can see your device, then pass the package name to `patch-apk`.

```
$ python3 patch-apk.py com.whatsapp
$ patch-apk com.whatsapp
Getting APK path(s) for package: com.whatsapp
[+] APK path: /data/app/com.whatsapp-NKLgchoExRFTDLkkbDqBGg==/base.apk

Expand All @@ -70,12 +93,12 @@ Installing the patched APK to the device.
Done, cleaning up temporary files.
```

When `patch-apk.py` is done, the installed app should be patched with objection and have support for user-installed CA certificates enabled. Launch the app on the device and run `objection explore` as you normally would to connect to the agent.
When `patch-apk` is done, the installed app should be patched with objection and have support for user-installed CA certificates enabled. Launch the app on the device and run `objection explore` as you normally would to connect to the agent.

**Partial Package Name Matching:** Pass a partial package name to `patch-apk.py` and it'll automatically grab the correct package name or ask you to confirm from available options.
**Partial Package Name Matching:** Pass a partial package name to `patch-apk` and it'll automatically grab the correct package name or ask you to confirm from available options.

```
$ python3 patch-apk.py proxy
$ patch-apk proxy

[!] Multiple matching packages installed, select the package to patch.

Expand All @@ -100,7 +123,7 @@ package:/data/app/~~TP7sglBuEoDc3yH0wpZdiA==/org.proxydroid-PCy1JxTMVJT3KmxVqaag
The following shows `patch-apk.py` detecting, rebuilding, and patching a split APK. Some output has been snipped for brevity. The `-v` flag has been set to show additional info.

```
$ python3 patch-apk.py org.proxydroid -v
$ patch-apk org.proxydroid -v

[+] Retrieving APK path(s) for package: org.proxydroid
[+] APK path: /data/app/~~FTVBmscrJiLerJdXIEa5tw==/org.proxydroid-KMq91nU1y9Qz8ZZAGM--RA==/base.apk
Expand All @@ -127,7 +150,7 @@ $ python3 patch-apk.py org.proxydroid -v
Extracted: /var/folders/t3/vz305z151ng8y2rwvpkx28xw0000gn/T/tmpyw7wl64i/org.proxydroid-split_config.en.apk
Extracted: /var/folders/t3/vz305z151ng8y2rwvpkx28xw0000gn/T/tmpyw7wl64i/org.proxydroid-split_config.fr.apk
Extracted: /var/folders/t3/vz305z151ng8y2rwvpkx28xw0000gn/T/tmpyw7wl64i/org.proxydroid-split_config.nl.apk
Extracted: /var/folders/t3/vz305z151ng8y2rwvpkx28xw0000gn/T/tmpyw7wl64i/org.proxydroid-split_config.xxhdpi.apk
Extracted: /var/folders/t3/vz305z151ng8y2rwvpkx28xw0000gn/T/tmpyw7wl64xk/org.proxydroid-split_config.xxhdpi.apk

[+] Rebuilding as a single APK

Expand Down Expand Up @@ -168,7 +191,7 @@ package:/data/app/org.proxydroid-9NuZnT-lK3qM_IZQEHhTgA==/base.apk
By default, patch-apk will inject the frida gadget and modify the network security config. It is also possible to only perform an extraction by providing the `--extract-only` flag. Any split apks will still be merged and a local copy of the APK will be produced:

```
$ python3 patch-apk.py org.proxydroid --extract-only
$ patch-apk org.proxydroid --extract-only

[+] Retrieving APK path(s) for package: org.proxydroid

Expand Down Expand Up @@ -196,7 +219,7 @@ package:/data/app/~~TP7sglBuEoDc3yH0wpZdiA==/org.proxydroid-PCy1JxTMVJT3KmxVqaag
package:/data/app/~~TP7sglBuEoDc3yH0wpZdiA==/org.proxydroid-PCy1JxTMVJT3KmxVqaagGQ==/split_config.xxhdpi.apk
```

These can be combined into a single APK for use with other tools such as `objection patchapk`. This is done by `patch-apk.py` as follows:
These can be combined into a single APK for use with other tools such as `objection patchapk`. This is done by `patch-apk` as follows:

**Step 1 - Extract APKs:** First, the individual APK files are pulled from the device and extracted using `apktool`.

Expand Down
50 changes: 50 additions & 0 deletions README_PROJECT_LAYOUT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## Project layout

The primary source package lives under `src/patch_apk/`. The following lists the source tree with files inside the `config`, `core`, and `utils` subfolders.

```
src/
├─ .vscode/
│ └─ PythonImportHelper-v2-Completion.json
├─ patch_apk/
│ ├─ __init__.py
│ ├─ main.py
│ ├─ config/
│ │ ├─ __init__.py
│ │ └─ constants.py
│ ├─ core/
│ │ ├─ __init__.py
│ │ ├─ apk_builder.py
│ │ └─ apk_tool.py
│ └─ utils/
│ ├─ __init__.py
│ ├─ apk_detect_proguard.py
│ ├─ cli_tools.py
│ ├─ copy_split_apks.py
│ ├─ dependencies.py
│ ├─ disable_apk_split.py
│ ├─ fix_private_resources.py
│ ├─ fix_resource_id.py
│ ├─ frida_objection.py
│ ├─ get_apk_paths.py
│ ├─ get_target_apk.py
│ ├─ raw_re_replace.py
│ ├─ remove_duplicate_style.py
│ ├─ verify_package_name.py
│ └─ data/
│ └─ patch-apk.keystore
└─ patch_apk.egg-info/
├─ dependency_links.txt
├─ entry_points.txt
├─ PKG-INFO
├─ requires.txt
├─ SOURCES.txt
└─ top_level.txt
```

Notes:

- Files inside `src/patch_apk/core/` are implemented in a class-based style (for example `APKTool`, `APKBuilder`, etc.).
- Files inside `src/patch_apk/utils/` are implemented as modules of helper functions (function-based utilities used across the project).

The package version is defined in `src/patch_apk/__init__.py` (`__version__`).
Binary file modified requirements.txt
Binary file not shown.
Loading