GAPBF is a Linux-first Python CLI for brute-forcing Android pattern locks through TWRP recovery using a graph-based path generator.
It is intended for legitimate device recovery scenarios where you control the device, can boot into TWRP, and want to constrain the search space using partial knowledge of the original unlock pattern.
- Typer-based CLI with Rich output
- SQLite-backed run history and attempt persistence
- Resume-aware status reporting
- Geometric path generation with Android-style blocker rules plus optional user-defined distance pruning
- Tested with
pytestand packaged viauv
- Linux-focused workflow
- Requires
adbaccess to a device already booted into TWRP - TWRP enforces an effective per-attempt delay; this project does not bypass that limit
- Large search spaces are still expensive, so partial pattern knowledge matters
- 6x6 pattern support is still based on an assumed mapping and should be treated as experimental
GAPBF generates valid pattern paths for Android-style grids and evaluates them through one or more handlers:
a: send attempts to TWRP viaadb shell twrp decrypt ...p: print generated paths for inspection/debuggingt: compare generated paths against a configured test path
Run and attempt metadata is stored in SQLite so interrupted sessions can be inspected later with the CLI.
- Linux
- Python 3.11 or newer
uvadb- A device with pattern lock support and TWRP recovery available
git clone git@github.com:robin-scharf/gapbf.git
cd gapbf
uv sync --dev
cp config.example.yaml config.yaml
uv run pre-commit install
uv run pre-commit install --hook-type pre-pushThis repo uses pre-commit as the Python equivalent of Husky:
pre-commitrunsruff checkandmypybefore each commitpre-pushruns the fullpytestsuite before each push
Run the hooks across the whole repository at any time with:
uv run pre-commit run --all-files
uv run pre-commit run --hook-stage pre-push --all-filesInspect the available commands:
uv run gapbf --helpCheck that the device is visible to ADB/TWRP:
adb devices
uv run gapbf check-deviceReview current configuration and resume state:
uv run gapbf statusLaunch the local web UI:
uv run gapbf web
uv run gapbf web --config config.yaml --host 127.0.0.1 --port 8000Run the brute-force process:
uv run gapbf run -m aUse combined modes when needed:
uv run gapbf run -m ap
uv run gapbf run -m tReview stored run history:
uv run gapbf history
uv run gapbf history --limit 10Legacy-compatible invocation is still supported:
uv run gapbf -m apThis repository ships a template config at config.example.yaml.
Create your local runtime config with:
cp config.example.yaml config.yamlconfig.yaml is intentionally gitignored so device-specific settings, path constraints, and local runtime values stay out of commits.
Runtime configuration is loaded from config.yaml by default.
Important fields include:
grid_sizepath_min_lengthpath_max_lengthpath_max_node_distancepath_prefixpath_suffixexcluded_nodesattempt_delayadb_timeoutdb_pathstdout_normalstdout_successstdout_error
path_max_node_distance is a user-defined search limiter, not part of the
underlying blocker legality check. It caps how far a single move may travel in
grid coordinates.
1keeps moves to direct neighborsgrid_size - 1allows the full theoretical move range for the selected grid- intermediate values intentionally prune longer jumps to reduce the search space
By default, GAPBF now uses the theoretical maximum for the selected grid, so a 3x3 config defaults to 2, a 4x4 config to 3, and so on up to 5 for 6x6.
The web UI exposes the same configuration surface with grid-aware limits and live validation. Prefix and suffix segments can be drawn directly on the board, excluded nodes can be toggled visually, and run progress plus attempt logs stream back into the browser while a search is active.
Constrain the pattern space as aggressively as possible. Prefixes, suffixes, excluded nodes, and realistic path lengths have a much larger effect on runtime than implementation-level optimizations because TWRP remains the throughput bottleneck.
GAPBF supports 3x3, 4x4, 5x5, and 6x6 pattern grids. Availability of non-3x3 grids depends on the device, ROM, and recovery implementation you are working with, so treat the larger layouts as environment-dependent rather than assuming every Android build exposes the same settings UI.
Example 3x3 grid:
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
Example 4x4 grid:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, :, ;, <],
[=, >, ?, @]
]
Example 5x5 grid:
[
[1, 2, 3, 4, 5],
[6, 7, 8, 9, :],
[;, <, =, >, ?],
[@, A, B, C, D],
[E, F, G, H, I]
]
Current 6x6 assumption:
[
[1, 2, 3, 4, 5, 6],
[7, 8, 9, :, ;, <],
[=, >, ?, @, A, B],
[C, D, E, F, G, H],
[I, J, K, L, M, N],
[O, P, Q, R, S, T]
]
Run tests:
uv run python -m pytestRun the same quality gates used by the Git hooks:
uv run ruff check .
uv run mypy src
uv run pytestThe project is packaged from src/gapbf and exposes the gapbf console script via pyproject.toml.
See NEXT_STEPS.md for follow-up work, known gaps, and suggested improvements before broader public distribution.
This project is released under the GNU GPL-3.0 license. See LICENSE for details.