WIP
This commit is contained in:
parent
ba02e70dcc
commit
a6a0740c61
11 changed files with 466 additions and 171 deletions
160
frida/poetry.lock
generated
160
frida/poetry.lock
generated
|
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "alembic"
|
||||
|
|
@ -18,7 +18,7 @@ SQLAlchemy = ">=1.3.0"
|
|||
typing-extensions = ">=4"
|
||||
|
||||
[package.extras]
|
||||
tz = ["backports.zoneinfo ; python_version < \"3.9\"", "tzdata"]
|
||||
tz = ["backports.zoneinfo", "tzdata"]
|
||||
|
||||
[[package]]
|
||||
name = "androguard"
|
||||
|
|
@ -132,6 +132,25 @@ files = [
|
|||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coloredlogs"
|
||||
version = "15.0.1"
|
||||
description = "Colored terminal output for Python's logging module"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
groups = ["main"]
|
||||
markers = "extra == \"grodd\""
|
||||
files = [
|
||||
{file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"},
|
||||
{file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
humanfriendly = ">=9.1"
|
||||
|
||||
[package.extras]
|
||||
cron = ["capturer (>=2.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "contourpy"
|
||||
version = "1.3.1"
|
||||
|
|
@ -267,7 +286,7 @@ files = [
|
|||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
|
||||
|
||||
[[package]]
|
||||
name = "fonttools"
|
||||
|
|
@ -330,18 +349,18 @@ files = [
|
|||
]
|
||||
|
||||
[package.extras]
|
||||
all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"]
|
||||
all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"]
|
||||
graphite = ["lz4 (>=1.7.4.2)"]
|
||||
interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""]
|
||||
interpolatable = ["munkres", "pycairo", "scipy"]
|
||||
lxml = ["lxml (>=4.0)"]
|
||||
pathops = ["skia-pathops (>=0.5.0)"]
|
||||
plot = ["matplotlib"]
|
||||
repacker = ["uharfbuzz (>=0.23.0)"]
|
||||
symfont = ["sympy"]
|
||||
type1 = ["xattr ; sys_platform == \"darwin\""]
|
||||
type1 = ["xattr"]
|
||||
ufo = ["fs (>=2.2.0,<3)"]
|
||||
unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""]
|
||||
woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"]
|
||||
unicode = ["unicodedata2 (>=15.1.0)"]
|
||||
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "frida"
|
||||
|
|
@ -472,6 +491,44 @@ files = [
|
|||
docs = ["Sphinx", "furo"]
|
||||
test = ["objgraph", "psutil"]
|
||||
|
||||
[[package]]
|
||||
name = "grodd-runner"
|
||||
version = "0.1.0"
|
||||
description = "Grodd runner is a python program that tries to browse all activities of an Android application."
|
||||
optional = true
|
||||
python-versions = ">=3.11,<4.0.0"
|
||||
groups = ["main"]
|
||||
markers = "extra == \"grodd\""
|
||||
files = []
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
coloredlogs = ">=15.0.1,<16.0.0"
|
||||
networkx = ">=3.4.2,<4.0.0"
|
||||
uiautomator = ">=1.0.2,<2.0.0"
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "ssh://git@gitlab.inria.fr/CIDRE/malware/grodd-runner.git"
|
||||
reference = "HEAD"
|
||||
resolved_reference = "323cabc4e92a89fc9bcd23231c11764a6e423a52"
|
||||
|
||||
[[package]]
|
||||
name = "humanfriendly"
|
||||
version = "10.0"
|
||||
description = "Human friendly output for text interfaces using Python"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
groups = ["main"]
|
||||
markers = "extra == \"grodd\""
|
||||
files = [
|
||||
{file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
|
||||
{file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "ipython"
|
||||
version = "8.32.0"
|
||||
|
|
@ -498,7 +555,7 @@ traitlets = ">=5.13.0"
|
|||
[package.extras]
|
||||
all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"]
|
||||
black = ["black"]
|
||||
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"]
|
||||
doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing_extensions"]
|
||||
kernel = ["ipykernel"]
|
||||
matplotlib = ["matplotlib"]
|
||||
nbconvert = ["nbconvert"]
|
||||
|
|
@ -636,7 +693,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
|
|||
win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
|
||||
|
||||
[package.extras]
|
||||
dev = ["Sphinx (==8.1.3) ; python_version >= \"3.11\"", "build (==1.2.2) ; python_version >= \"3.11\"", "colorama (==0.4.5) ; python_version < \"3.8\"", "colorama (==0.4.6) ; python_version >= \"3.8\"", "exceptiongroup (==1.1.3) ; python_version >= \"3.7\" and python_version < \"3.11\"", "freezegun (==1.1.0) ; python_version < \"3.8\"", "freezegun (==1.5.0) ; python_version >= \"3.8\"", "mypy (==v0.910) ; python_version < \"3.6\"", "mypy (==v0.971) ; python_version == \"3.6\"", "mypy (==v1.13.0) ; python_version >= \"3.8\"", "mypy (==v1.4.1) ; python_version == \"3.7\"", "myst-parser (==4.0.0) ; python_version >= \"3.11\"", "pre-commit (==4.0.1) ; python_version >= \"3.9\"", "pytest (==6.1.2) ; python_version < \"3.8\"", "pytest (==8.3.2) ; python_version >= \"3.8\"", "pytest-cov (==2.12.1) ; python_version < \"3.8\"", "pytest-cov (==5.0.0) ; python_version == \"3.8\"", "pytest-cov (==6.0.0) ; python_version >= \"3.9\"", "pytest-mypy-plugins (==1.9.3) ; python_version >= \"3.6\" and python_version < \"3.8\"", "pytest-mypy-plugins (==3.1.0) ; python_version >= \"3.8\"", "sphinx-rtd-theme (==3.0.2) ; python_version >= \"3.11\"", "tox (==3.27.1) ; python_version < \"3.8\"", "tox (==4.23.2) ; python_version >= \"3.8\"", "twine (==6.0.1) ; python_version >= \"3.11\""]
|
||||
dev = ["Sphinx (==8.1.3)", "build (==1.2.2)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.5.0)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.13.0)", "mypy (==v1.4.1)", "myst-parser (==4.0.0)", "pre-commit (==4.0.1)", "pytest (==6.1.2)", "pytest (==8.3.2)", "pytest-cov (==2.12.1)", "pytest-cov (==5.0.0)", "pytest-cov (==6.0.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.1.0)", "sphinx-rtd-theme (==3.0.2)", "tox (==3.27.1)", "tox (==4.23.2)", "twine (==6.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "lxml"
|
||||
|
|
@ -1213,7 +1270,7 @@ docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline
|
|||
fpx = ["olefile"]
|
||||
mic = ["olefile"]
|
||||
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"]
|
||||
typing = ["typing-extensions ; python_version < \"3.10\""]
|
||||
typing = ["typing-extensions"]
|
||||
xmp = ["defusedxml"]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1309,6 +1366,22 @@ files = [
|
|||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pyreadline3"
|
||||
version = "3.5.4"
|
||||
description = "A python implementation of GNU readline."
|
||||
optional = true
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
markers = "sys_platform == \"win32\" and extra == \"grodd\""
|
||||
files = [
|
||||
{file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"},
|
||||
{file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["build", "flake8", "mypy", "pytest", "twine"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
|
|
@ -1457,25 +1530,25 @@ files = [
|
|||
greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
|
||||
|
||||
[package.extras]
|
||||
aiomysql = ["aiomysql (>=0.2.0) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
||||
aiosqlite = ["aiosqlite ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\"", "typing_extensions (!=3.10.0.1)"]
|
||||
asyncio = ["greenlet (!=0.4.17) ; python_version >= \"3\""]
|
||||
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
||||
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2) ; python_version >= \"3\"", "mariadb (>=1.0.1,!=1.1.2) ; python_version >= \"3\""]
|
||||
aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
|
||||
aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
|
||||
asyncio = ["greenlet (!=0.4.17)"]
|
||||
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"]
|
||||
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)", "mariadb (>=1.0.1,!=1.1.2)"]
|
||||
mssql = ["pyodbc"]
|
||||
mssql-pymssql = ["pymssql", "pymssql"]
|
||||
mssql-pyodbc = ["pyodbc", "pyodbc"]
|
||||
mypy = ["mypy (>=0.910) ; python_version >= \"3\"", "sqlalchemy2-stubs"]
|
||||
mysql = ["mysqlclient (>=1.4.0) ; python_version >= \"3\"", "mysqlclient (>=1.4.0,<2) ; python_version < \"3\""]
|
||||
mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"]
|
||||
mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"]
|
||||
mysql-connector = ["mysql-connector-python", "mysql-connector-python"]
|
||||
oracle = ["cx_oracle (>=7) ; python_version >= \"3\"", "cx_oracle (>=7,<8) ; python_version < \"3\""]
|
||||
oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"]
|
||||
postgresql = ["psycopg2 (>=2.7)"]
|
||||
postgresql-asyncpg = ["asyncpg ; python_version >= \"3\"", "asyncpg ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
||||
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0) ; python_version >= \"3\"", "pg8000 (>=1.16.6,!=1.29.0) ; python_version >= \"3\""]
|
||||
postgresql-asyncpg = ["asyncpg", "asyncpg", "greenlet (!=0.4.17)", "greenlet (!=0.4.17)"]
|
||||
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)", "pg8000 (>=1.16.6,!=1.29.0)"]
|
||||
postgresql-psycopg2binary = ["psycopg2-binary"]
|
||||
postgresql-psycopg2cffi = ["psycopg2cffi"]
|
||||
pymysql = ["pymysql (<1) ; python_version < \"3\"", "pymysql ; python_version >= \"3\""]
|
||||
sqlcipher = ["sqlcipher3_binary ; python_version >= \"3\""]
|
||||
pymysql = ["pymysql", "pymysql (<1)"]
|
||||
sqlcipher = ["sqlcipher3_binary"]
|
||||
|
||||
[[package]]
|
||||
name = "stack-data"
|
||||
|
|
@ -1525,6 +1598,40 @@ files = [
|
|||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uiautomator"
|
||||
version = "1.0.2"
|
||||
description = "Python Wrapper for Android UiAutomator test tool"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
markers = "extra == \"grodd\""
|
||||
files = [
|
||||
{file = "uiautomator-1.0.2.tar.gz", hash = "sha256:48a41c36f8347b643ff215d41b73ab2b4f542a0e3f7b110b85f7952b70742744"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
urllib3 = ">=1.7.1"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.3.0"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = true
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
markers = "extra == \"grodd\""
|
||||
files = [
|
||||
{file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"},
|
||||
{file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
||||
h2 = ["h2 (>=4,<5)"]
|
||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.13"
|
||||
|
|
@ -1647,9 +1754,12 @@ files = [
|
|||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"]
|
||||
dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
|
||||
|
||||
[extras]
|
||||
grodd = ["grodd-runner"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.13,<4.0.0"
|
||||
content-hash = "5f31562f74268b8fd66962ef54ae7ac09e50583c27137cccf77230d2c1461c2d"
|
||||
content-hash = "bc0db0a87a5eb37d349706b948be90506f3bd5925e6262df600cbdffa3b116fe"
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ dependencies = [
|
|||
]
|
||||
|
||||
|
||||
[project.optional-dependencies]
|
||||
grodd = ["grodd-runner @ git+ssh://git@gitlab.inria.fr/CIDRE/malware/grodd-runner.git"]
|
||||
[build-system]
|
||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ FRIDA_SERVER_BIN = Path(__file__).parent / "frida-server-16.7.0-android-x86_64.x
|
|||
FRIDA_SERVER_ANDROID_PATH = "/data/local/tmp/frida-server"
|
||||
|
||||
|
||||
def setup_frida(device_name: str, env: dict[str, str]) -> frida.core.Device:
|
||||
def setup_frida(device_name: str, env: dict[str, str], adb: str) -> frida.core.Device:
|
||||
if device_name != "":
|
||||
device = frida.get_device(device_name)
|
||||
env["ANDROID_SERIAL"] = device_name
|
||||
|
|
@ -250,21 +250,21 @@ def setup_frida(device_name: str, env: dict[str, str]) -> frida.core.Device:
|
|||
# Start server
|
||||
proc: subprocess.CompletedProcess[str] | subprocess.CompletedProcess[bytes] = (
|
||||
subprocess.run(
|
||||
["adb", "shell", "whoami"],
|
||||
[adb, "shell", "whoami"],
|
||||
encoding="utf-8",
|
||||
stdout=subprocess.PIPE,
|
||||
env=env,
|
||||
)
|
||||
)
|
||||
if proc.stdout.strip() != "root":
|
||||
proc = subprocess.run(["adb", "root"], env=env)
|
||||
proc = subprocess.run([adb, "root"], env=env)
|
||||
# Rooting adb will disconnect the device
|
||||
if device_name != "":
|
||||
device = frida.get_device(device_name)
|
||||
else:
|
||||
device = frida.get_usb_device()
|
||||
perm = subprocess.run(
|
||||
["adb", "shell", "stat", "-c", "%a", FRIDA_SERVER_ANDROID_PATH],
|
||||
[adb, "shell", "stat", "-c", "%a", FRIDA_SERVER_ANDROID_PATH],
|
||||
encoding="utf-8",
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
|
|
@ -287,7 +287,7 @@ def setup_frida(device_name: str, env: dict[str, str]) -> frida.core.Device:
|
|||
|
||||
subprocess.run(
|
||||
[
|
||||
"adb",
|
||||
adb,
|
||||
"push",
|
||||
str((tmpd / "frida-server").absolute()),
|
||||
FRIDA_SERVER_ANDROID_PATH,
|
||||
|
|
@ -296,9 +296,9 @@ def setup_frida(device_name: str, env: dict[str, str]) -> frida.core.Device:
|
|||
)
|
||||
if need_perm_resset:
|
||||
subprocess.run(
|
||||
["adb", "shell", "chmod", "755", FRIDA_SERVER_ANDROID_PATH], env=env
|
||||
[adb, "shell", "chmod", "755", FRIDA_SERVER_ANDROID_PATH], env=env
|
||||
)
|
||||
subprocess.Popen(["adb", "shell", FRIDA_SERVER_ANDROID_PATH], env=env)
|
||||
subprocess.Popen([adb, "shell", FRIDA_SERVER_ANDROID_PATH], env=env)
|
||||
# The server take some time to start
|
||||
# time.sleep(3)
|
||||
t = spinner()
|
||||
|
|
@ -313,23 +313,39 @@ def setup_frida(device_name: str, env: dict[str, str]) -> frida.core.Device:
|
|||
time.sleep(0.3)
|
||||
|
||||
|
||||
def collect_runtime(apk: Path, device_name: str, file_storage: Path, output: TextIO):
|
||||
def collect_runtime(
|
||||
apk: Path,
|
||||
device_name: str,
|
||||
file_storage: Path,
|
||||
output: TextIO,
|
||||
adb_path: Path | None = None,
|
||||
android_sdk_path: Path | None = None,
|
||||
):
|
||||
env = dict(os.environ)
|
||||
|
||||
if adb_path is not None:
|
||||
adb = str(adb_path)
|
||||
elif adb_path is None and android_sdk_path is None:
|
||||
adb = "adb"
|
||||
elif not (android_sdk_path / "platform-tools" / "adb").exists():
|
||||
adb = "adb"
|
||||
else:
|
||||
adb = str(android_sdk_path / "platform-tools" / "adb")
|
||||
|
||||
if not file_storage.exists():
|
||||
file_storage.mkdir(parents=True)
|
||||
if not file_storage.is_dir():
|
||||
print("[!] file_storage must be a directory")
|
||||
exit()
|
||||
|
||||
device = setup_frida(device_name, env)
|
||||
device = setup_frida(device_name, env, adb)
|
||||
|
||||
app = get_apkid(apk)[0]
|
||||
|
||||
if device.enumerate_applications([app]):
|
||||
# Uninstall the APK if it already exist
|
||||
subprocess.run(["adb", "uninstall", app], env=env)
|
||||
subprocess.run(["adb", "install", str(apk.absolute())], env=env)
|
||||
subprocess.run([adb, "uninstall", app], env=env)
|
||||
subprocess.run([adb, "install", str(apk.absolute())], env=env)
|
||||
|
||||
with FRIDA_SCRIPT.open("r") as file:
|
||||
jsscript = file.read()
|
||||
|
|
@ -380,7 +396,7 @@ def collect_runtime(apk: Path, device_name: str, file_storage: Path, output: Tex
|
|||
# time.sleep(0.3)
|
||||
# print(f"[*] Classloader list received" + " " * 20)
|
||||
|
||||
explore_app()
|
||||
explore_app(app, device=device.id, android_sdk=android_sdk_path)
|
||||
|
||||
# Try to find the Main class loader
|
||||
main_class_loader: str | None = None
|
||||
|
|
|
|||
|
|
@ -1,5 +1,28 @@
|
|||
def explore_app():
|
||||
manual_exploration()
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from grodd_runner import grodd_runner # type: ignore
|
||||
|
||||
USE_GRODD = True
|
||||
except ModuleNotFoundError:
|
||||
USE_GRODD = False
|
||||
|
||||
|
||||
def explore_app(
|
||||
package: str,
|
||||
device: str = "emulator-5554",
|
||||
android_sdk: Path | None = None,
|
||||
):
|
||||
if USE_GRODD:
|
||||
grodd_runner(
|
||||
"grodd", device, timeout=300, package=package, android_sdk=android_sdk
|
||||
)
|
||||
|
||||
else:
|
||||
print(
|
||||
"\033[31mGrodd is not available, you need to explore the app manually\033[0m"
|
||||
)
|
||||
manual_exploration()
|
||||
|
||||
|
||||
def manual_exploration():
|
||||
|
|
|
|||
4
theseus_autopatcher/.gitignore
vendored
4
theseus_autopatcher/.gitignore
vendored
|
|
@ -1,2 +1,2 @@
|
|||
# Created by venv; see https://docs.python.org/3/library/venv.html
|
||||
*
|
||||
dist/
|
||||
src/theseus_autopatcher/patcher_86_64_musl
|
||||
|
|
|
|||
11
theseus_autopatcher/build.sh
Normal file
11
theseus_autopatcher/build.sh
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
#rustup target add x86_64-unknown-linux-musl
|
||||
#doas pacman -S musl
|
||||
|
||||
FOLDER=$(dirname "$(realpath $0)")
|
||||
|
||||
env --chdir "${FOLDER}/../patcher" cargo build --release --target=x86_64-unknown-linux-musl
|
||||
cp "${FOLDER}/../patcher/target/x86_64-unknown-linux-musl/release/patcher" "${FOLDER}/src/theseus_autopatcher/patcher_86_64_musl"
|
||||
|
||||
env --chdir "${FOLDER}" poetry build
|
||||
154
theseus_autopatcher/poetry.lock
generated
154
theseus_autopatcher/poetry.lock
generated
|
|
@ -1,4 +1,4 @@
|
|||
# This file is automatically @generated by Poetry 2.1.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 2.0.1 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "alembic"
|
||||
|
|
@ -213,6 +213,24 @@ files = [
|
|||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coloredlogs"
|
||||
version = "15.0.1"
|
||||
description = "Colored terminal output for Python's logging module"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "coloredlogs-15.0.1-py2.py3-none-any.whl", hash = "sha256:612ee75c546f53e92e70049c9dbfcc18c935a2b9a53b66085ce9ef6a6e5c0934"},
|
||||
{file = "coloredlogs-15.0.1.tar.gz", hash = "sha256:7c991aa71a4577af2f82600d8f8f3a89f936baeaf9b50a9c197da014e5bf16b0"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
humanfriendly = ">=9.1"
|
||||
|
||||
[package.extras]
|
||||
cron = ["capturer (>=2.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "contourpy"
|
||||
version = "1.3.1"
|
||||
|
|
@ -336,10 +354,10 @@ files = [
|
|||
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
|
||||
|
||||
[package.extras]
|
||||
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0) ; python_version >= \"3.8\""]
|
||||
docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=3.0.0)"]
|
||||
docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"]
|
||||
nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_version >= \"3.8\""]
|
||||
pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"]
|
||||
nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"]
|
||||
pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"]
|
||||
sdist = ["build (>=1.0.0)"]
|
||||
ssh = ["bcrypt (>=3.1.5)"]
|
||||
test = ["certifi (>=2024)", "cryptography-vectors (==44.0.2)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"]
|
||||
|
|
@ -406,7 +424,7 @@ files = [
|
|||
]
|
||||
|
||||
[package.extras]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""]
|
||||
tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"]
|
||||
|
||||
[[package]]
|
||||
name = "fonttools"
|
||||
|
|
@ -469,18 +487,18 @@ files = [
|
|||
]
|
||||
|
||||
[package.extras]
|
||||
all = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\"", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0) ; python_version <= \"3.12\"", "xattr ; sys_platform == \"darwin\"", "zopfli (>=0.1.4)"]
|
||||
all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"]
|
||||
graphite = ["lz4 (>=1.7.4.2)"]
|
||||
interpolatable = ["munkres ; platform_python_implementation == \"PyPy\"", "pycairo", "scipy ; platform_python_implementation != \"PyPy\""]
|
||||
interpolatable = ["munkres", "pycairo", "scipy"]
|
||||
lxml = ["lxml (>=4.0)"]
|
||||
pathops = ["skia-pathops (>=0.5.0)"]
|
||||
plot = ["matplotlib"]
|
||||
repacker = ["uharfbuzz (>=0.23.0)"]
|
||||
symfont = ["sympy"]
|
||||
type1 = ["xattr ; sys_platform == \"darwin\""]
|
||||
type1 = ["xattr"]
|
||||
ufo = ["fs (>=2.2.0,<3)"]
|
||||
unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""]
|
||||
woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"]
|
||||
unicode = ["unicodedata2 (>=15.1.0)"]
|
||||
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
||||
|
||||
[[package]]
|
||||
name = "frida"
|
||||
|
|
@ -611,6 +629,42 @@ files = [
|
|||
docs = ["Sphinx", "furo"]
|
||||
test = ["objgraph", "psutil"]
|
||||
|
||||
[[package]]
|
||||
name = "grodd-runner"
|
||||
version = "0.1.0"
|
||||
description = "Grodd runner is a python program that tries to browse all activities of an Android application."
|
||||
optional = true
|
||||
python-versions = ">=3.11,<4.0.0"
|
||||
groups = ["main"]
|
||||
files = []
|
||||
develop = false
|
||||
|
||||
[package.dependencies]
|
||||
coloredlogs = ">=15.0.1,<16.0.0"
|
||||
networkx = ">=3.4.2,<4.0.0"
|
||||
uiautomator = ">=1.0.2,<2.0.0"
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "ssh://git@gitlab.inria.fr/CIDRE/malware/grodd-runner.git"
|
||||
reference = "HEAD"
|
||||
resolved_reference = "323cabc4e92a89fc9bcd23231c11764a6e423a52"
|
||||
|
||||
[[package]]
|
||||
name = "humanfriendly"
|
||||
version = "10.0"
|
||||
description = "Human friendly output for text interfaces using Python"
|
||||
optional = true
|
||||
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "humanfriendly-10.0-py2.py3-none-any.whl", hash = "sha256:1697e1a8a8f550fd43c2865cd84542fc175a61dcb779b6fee18cf6b6ccba1477"},
|
||||
{file = "humanfriendly-10.0.tar.gz", hash = "sha256:6b0b831ce8f15f7300721aa49829fc4e83921a9a301cc7f606be6686a2288ddc"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_version >= \"3.8\""}
|
||||
|
||||
[[package]]
|
||||
name = "ipython"
|
||||
version = "9.0.2"
|
||||
|
|
@ -785,7 +839,7 @@ colorama = {version = ">=0.3.4", markers = "sys_platform == \"win32\""}
|
|||
win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
|
||||
|
||||
[package.extras]
|
||||
dev = ["Sphinx (==8.1.3) ; python_version >= \"3.11\"", "build (==1.2.2) ; python_version >= \"3.11\"", "colorama (==0.4.5) ; python_version < \"3.8\"", "colorama (==0.4.6) ; python_version >= \"3.8\"", "exceptiongroup (==1.1.3) ; python_version >= \"3.7\" and python_version < \"3.11\"", "freezegun (==1.1.0) ; python_version < \"3.8\"", "freezegun (==1.5.0) ; python_version >= \"3.8\"", "mypy (==v0.910) ; python_version < \"3.6\"", "mypy (==v0.971) ; python_version == \"3.6\"", "mypy (==v1.13.0) ; python_version >= \"3.8\"", "mypy (==v1.4.1) ; python_version == \"3.7\"", "myst-parser (==4.0.0) ; python_version >= \"3.11\"", "pre-commit (==4.0.1) ; python_version >= \"3.9\"", "pytest (==6.1.2) ; python_version < \"3.8\"", "pytest (==8.3.2) ; python_version >= \"3.8\"", "pytest-cov (==2.12.1) ; python_version < \"3.8\"", "pytest-cov (==5.0.0) ; python_version == \"3.8\"", "pytest-cov (==6.0.0) ; python_version >= \"3.9\"", "pytest-mypy-plugins (==1.9.3) ; python_version >= \"3.6\" and python_version < \"3.8\"", "pytest-mypy-plugins (==3.1.0) ; python_version >= \"3.8\"", "sphinx-rtd-theme (==3.0.2) ; python_version >= \"3.11\"", "tox (==3.27.1) ; python_version < \"3.8\"", "tox (==4.23.2) ; python_version >= \"3.8\"", "twine (==6.0.1) ; python_version >= \"3.11\""]
|
||||
dev = ["Sphinx (==8.1.3)", "build (==1.2.2)", "colorama (==0.4.5)", "colorama (==0.4.6)", "exceptiongroup (==1.1.3)", "freezegun (==1.1.0)", "freezegun (==1.5.0)", "mypy (==v0.910)", "mypy (==v0.971)", "mypy (==v1.13.0)", "mypy (==v1.4.1)", "myst-parser (==4.0.0)", "pre-commit (==4.0.1)", "pytest (==6.1.2)", "pytest (==8.3.2)", "pytest-cov (==2.12.1)", "pytest-cov (==5.0.0)", "pytest-cov (==6.0.0)", "pytest-mypy-plugins (==1.9.3)", "pytest-mypy-plugins (==3.1.0)", "sphinx-rtd-theme (==3.0.2)", "tox (==3.27.1)", "tox (==4.23.2)", "twine (==6.0.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "lxml"
|
||||
|
|
@ -1347,7 +1401,7 @@ docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline
|
|||
fpx = ["olefile"]
|
||||
mic = ["olefile"]
|
||||
tests = ["check-manifest", "coverage (>=7.4.2)", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout", "trove-classifiers (>=2024.10.12)"]
|
||||
typing = ["typing-extensions ; python_version < \"3.10\""]
|
||||
typing = ["typing-extensions"]
|
||||
xmp = ["defusedxml"]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -1456,6 +1510,22 @@ files = [
|
|||
[package.extras]
|
||||
diagrams = ["jinja2", "railroad-diagrams"]
|
||||
|
||||
[[package]]
|
||||
name = "pyreadline3"
|
||||
version = "3.5.4"
|
||||
description = "A python implementation of GNU readline."
|
||||
optional = true
|
||||
python-versions = ">=3.8"
|
||||
groups = ["main"]
|
||||
markers = "sys_platform == \"win32\""
|
||||
files = [
|
||||
{file = "pyreadline3-3.5.4-py3-none-any.whl", hash = "sha256:eaf8e6cc3c49bcccf145fc6067ba8643d1df34d604a1ec0eccbf7a18e6d3fae6"},
|
||||
{file = "pyreadline3-3.5.4.tar.gz", hash = "sha256:8d57d53039a1c75adba8e50dd3d992b28143480816187ea5efbd5c78e6c885b7"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["build", "flake8", "mypy", "pytest", "twine"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dateutil"
|
||||
version = "2.9.0.post0"
|
||||
|
|
@ -1604,25 +1674,25 @@ files = [
|
|||
greenlet = {version = "!=0.4.17", markers = "python_version >= \"3\" and (platform_machine == \"aarch64\" or platform_machine == \"ppc64le\" or platform_machine == \"x86_64\" or platform_machine == \"amd64\" or platform_machine == \"AMD64\" or platform_machine == \"win32\" or platform_machine == \"WIN32\")"}
|
||||
|
||||
[package.extras]
|
||||
aiomysql = ["aiomysql (>=0.2.0) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
||||
aiosqlite = ["aiosqlite ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\"", "typing_extensions (!=3.10.0.1)"]
|
||||
asyncio = ["greenlet (!=0.4.17) ; python_version >= \"3\""]
|
||||
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
||||
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2) ; python_version >= \"3\"", "mariadb (>=1.0.1,!=1.1.2) ; python_version >= \"3\""]
|
||||
aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
|
||||
aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
|
||||
asyncio = ["greenlet (!=0.4.17)"]
|
||||
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"]
|
||||
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)", "mariadb (>=1.0.1,!=1.1.2)"]
|
||||
mssql = ["pyodbc"]
|
||||
mssql-pymssql = ["pymssql", "pymssql"]
|
||||
mssql-pyodbc = ["pyodbc", "pyodbc"]
|
||||
mypy = ["mypy (>=0.910) ; python_version >= \"3\"", "sqlalchemy2-stubs"]
|
||||
mysql = ["mysqlclient (>=1.4.0) ; python_version >= \"3\"", "mysqlclient (>=1.4.0,<2) ; python_version < \"3\""]
|
||||
mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"]
|
||||
mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"]
|
||||
mysql-connector = ["mysql-connector-python", "mysql-connector-python"]
|
||||
oracle = ["cx_oracle (>=7) ; python_version >= \"3\"", "cx_oracle (>=7,<8) ; python_version < \"3\""]
|
||||
oracle = ["cx_oracle (>=7)", "cx_oracle (>=7,<8)"]
|
||||
postgresql = ["psycopg2 (>=2.7)"]
|
||||
postgresql-asyncpg = ["asyncpg ; python_version >= \"3\"", "asyncpg ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
||||
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0) ; python_version >= \"3\"", "pg8000 (>=1.16.6,!=1.29.0) ; python_version >= \"3\""]
|
||||
postgresql-asyncpg = ["asyncpg", "asyncpg", "greenlet (!=0.4.17)", "greenlet (!=0.4.17)"]
|
||||
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)", "pg8000 (>=1.16.6,!=1.29.0)"]
|
||||
postgresql-psycopg2binary = ["psycopg2-binary"]
|
||||
postgresql-psycopg2cffi = ["psycopg2cffi"]
|
||||
pymysql = ["pymysql (<1) ; python_version < \"3\"", "pymysql ; python_version >= \"3\""]
|
||||
sqlcipher = ["sqlcipher3_binary ; python_version >= \"3\""]
|
||||
pymysql = ["pymysql", "pymysql (<1)"]
|
||||
sqlcipher = ["sqlcipher3_binary"]
|
||||
|
||||
[[package]]
|
||||
name = "stack-data"
|
||||
|
|
@ -1691,6 +1761,38 @@ files = [
|
|||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uiautomator"
|
||||
version = "1.0.2"
|
||||
description = "Python Wrapper for Android UiAutomator test tool"
|
||||
optional = true
|
||||
python-versions = "*"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "uiautomator-1.0.2.tar.gz", hash = "sha256:48a41c36f8347b643ff215d41b73ab2b4f542a0e3f7b110b85f7952b70742744"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
urllib3 = ">=1.7.1"
|
||||
|
||||
[[package]]
|
||||
name = "urllib3"
|
||||
version = "2.3.0"
|
||||
description = "HTTP library with thread-safe connection pooling, file post, and more."
|
||||
optional = true
|
||||
python-versions = ">=3.9"
|
||||
groups = ["main"]
|
||||
files = [
|
||||
{file = "urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df"},
|
||||
{file = "urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
|
||||
h2 = ["h2 (>=4,<5)"]
|
||||
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
|
||||
zstd = ["zstandard (>=0.18.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "wcwidth"
|
||||
version = "0.2.13"
|
||||
|
|
@ -1813,9 +1915,9 @@ files = [
|
|||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"]
|
||||
dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
|
||||
|
||||
[metadata]
|
||||
lock-version = "2.1"
|
||||
python-versions = ">=3.13,<4.0.0"
|
||||
content-hash = "8e014dd037fc84f3479bd8821c65d1afa5672d3c3c99f39a4024d5197d7b26bb"
|
||||
content-hash = "1bcf2198a037383d3d29aea2059caec389c58b17d89d17eb4ce8d5d9c71fa8b0"
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ requires-python = ">=3.13,<4.0.0"
|
|||
|
||||
[tool.poetry.dependencies]
|
||||
theseus-frida = { path = "../frida" }
|
||||
grodd-runner = {git = "ssh://git@gitlab.inria.fr/CIDRE/malware/grodd-runner.git", optional = true}
|
||||
|
||||
[tool.poetry.extras]
|
||||
grodd = ["grodd-runner"]
|
||||
|
||||
[tool.poetry]
|
||||
packages = [{include = "theseus_autopatcher", from = "src"}]
|
||||
|
|
|
|||
|
|
@ -7,87 +7,7 @@ from shutil import which
|
|||
|
||||
from theseus_frida import collect_runtime
|
||||
|
||||
|
||||
def spinner(symbs: str = "◜◠◝◞◡◟"):
|
||||
while True:
|
||||
for s in symbs:
|
||||
yield s
|
||||
|
||||
|
||||
def get_android_sdk_path() -> Path | None:
|
||||
if "ANDROID_HOME" in os.environ:
|
||||
return Path(os.environ["ANDROID_HOME"])
|
||||
default = Path.home() / "Android" / "Sdk"
|
||||
if default.exists():
|
||||
return default
|
||||
return None
|
||||
|
||||
|
||||
def get_build_tools_path(toolname: str) -> Path | None:
|
||||
def score_version(name: str):
|
||||
score = []
|
||||
for n in name.split("."):
|
||||
if n.isdecimal():
|
||||
score.append(int(n))
|
||||
else:
|
||||
score.append(-1)
|
||||
return score
|
||||
|
||||
path = which(toolname)
|
||||
if path is not None:
|
||||
return Path(path)
|
||||
path = which(toolname + ".exe")
|
||||
if path is not None:
|
||||
return Path(path)
|
||||
|
||||
sdk = get_android_sdk_path()
|
||||
if sdk is None:
|
||||
return None
|
||||
tools = sdk / "build-tools"
|
||||
if not tools.exists():
|
||||
return None
|
||||
options = []
|
||||
for d in tools.iterdir():
|
||||
if (d / toolname).exists():
|
||||
options.append(d / toolname)
|
||||
if (d / (toolname + ".exe")).exists():
|
||||
options.append(d / (toolname + ".exe"))
|
||||
if not options:
|
||||
return None
|
||||
return max(options, key=lambda d: score_version(d.parent.name))
|
||||
|
||||
|
||||
def get_keytool_path() -> Path | None:
|
||||
path = which("keytool")
|
||||
if path is not None:
|
||||
return Path(path)
|
||||
path = which("keytool.exe")
|
||||
if path is not None:
|
||||
return Path(path)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def gen_keystore(keytool: Path, storepath: Path):
|
||||
print(f"{str(storepath)} does not exist, creating it.")
|
||||
subprocess.run(
|
||||
[
|
||||
str(keytool),
|
||||
"-genkeypair",
|
||||
"-validity",
|
||||
"1000",
|
||||
"-dname",
|
||||
"CN=SomeKey,O=SomeOne,C=FR",
|
||||
"-keystore",
|
||||
str(storepath),
|
||||
"-alias",
|
||||
"SignKey",
|
||||
"-keyalg",
|
||||
"RSA",
|
||||
"-v",
|
||||
]
|
||||
)
|
||||
|
||||
from .utils import *
|
||||
|
||||
PATCHER_BIN_PATH = Path(__file__).parent / "patcher_86_64_musl"
|
||||
|
||||
|
|
@ -100,30 +20,24 @@ def patch_apk(
|
|||
apksigner: Path,
|
||||
keystore: Path,
|
||||
):
|
||||
def dbg(l):
|
||||
print(" ".join(l))
|
||||
return l
|
||||
|
||||
subprocess.run(
|
||||
dbg(
|
||||
[
|
||||
str(PATCHER_BIN_PATH.absolute()),
|
||||
"--runtime-data",
|
||||
str(runtime_data.absolute()),
|
||||
"--path",
|
||||
str(apk.absolute()),
|
||||
"--out",
|
||||
str(apkout.absolute()),
|
||||
"-k",
|
||||
str(keystore.absolute()),
|
||||
"-z",
|
||||
str(zipalign.absolute()),
|
||||
"-a",
|
||||
str(apksigner.absolute()),
|
||||
"--code-loading-patch-strategy",
|
||||
"model-class-loaders",
|
||||
]
|
||||
)
|
||||
[
|
||||
str(PATCHER_BIN_PATH.absolute()),
|
||||
"--runtime-data",
|
||||
str(runtime_data.absolute()),
|
||||
"--path",
|
||||
str(apk.absolute()),
|
||||
"--out",
|
||||
str(apkout.absolute()),
|
||||
"-k",
|
||||
str(keystore.absolute()),
|
||||
"-z",
|
||||
str(zipalign.absolute()),
|
||||
"-a",
|
||||
str(apksigner.absolute()),
|
||||
"--code-loading-patch-strategy",
|
||||
"model-class-loaders",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -228,6 +142,7 @@ def main():
|
|||
device_name=args.device,
|
||||
file_storage=tmpd / "dex",
|
||||
output=fp,
|
||||
android_sdk_path=get_android_sdk_path(),
|
||||
)
|
||||
patch_apk(
|
||||
runtime_data=tmpd / "runtime.json",
|
||||
|
|
|
|||
87
theseus_autopatcher/src/theseus_autopatcher/utils.py
Normal file
87
theseus_autopatcher/src/theseus_autopatcher/utils.py
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import os
|
||||
import argparse
|
||||
import subprocess
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from shutil import which
|
||||
|
||||
|
||||
def spinner(symbs: str = "-\\|/"):
|
||||
while True:
|
||||
for s in symbs:
|
||||
yield s
|
||||
|
||||
|
||||
def get_android_sdk_path() -> Path | None:
|
||||
if "ANDROID_HOME" in os.environ:
|
||||
return Path(os.environ["ANDROID_HOME"])
|
||||
default = Path.home() / "Android" / "Sdk"
|
||||
if default.exists():
|
||||
return default
|
||||
return None
|
||||
|
||||
|
||||
def get_build_tools_path(toolname: str) -> Path | None:
|
||||
def score_version(name: str):
|
||||
score = []
|
||||
for n in name.split("."):
|
||||
if n.isdecimal():
|
||||
score.append(int(n))
|
||||
else:
|
||||
score.append(-1)
|
||||
return score
|
||||
|
||||
path = which(toolname)
|
||||
if path is not None:
|
||||
return Path(path)
|
||||
path = which(toolname + ".exe")
|
||||
if path is not None:
|
||||
return Path(path)
|
||||
|
||||
sdk = get_android_sdk_path()
|
||||
if sdk is None:
|
||||
return None
|
||||
tools = sdk / "build-tools"
|
||||
if not tools.exists():
|
||||
return None
|
||||
options = []
|
||||
for d in tools.iterdir():
|
||||
if (d / toolname).exists():
|
||||
options.append(d / toolname)
|
||||
if (d / (toolname + ".exe")).exists():
|
||||
options.append(d / (toolname + ".exe"))
|
||||
if not options:
|
||||
return None
|
||||
return max(options, key=lambda d: score_version(d.parent.name))
|
||||
|
||||
|
||||
def get_keytool_path() -> Path | None:
|
||||
path = which("keytool")
|
||||
if path is not None:
|
||||
return Path(path)
|
||||
path = which("keytool.exe")
|
||||
if path is not None:
|
||||
return Path(path)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def gen_keystore(keytool: Path, storepath: Path):
|
||||
print(f"{str(storepath)} does not exist, creating it.")
|
||||
subprocess.run(
|
||||
[
|
||||
str(keytool),
|
||||
"-genkeypair",
|
||||
"-validity",
|
||||
"1000",
|
||||
"-dname",
|
||||
"CN=SomeKey,O=SomeOne,C=FR",
|
||||
"-keystore",
|
||||
str(storepath),
|
||||
"-alias",
|
||||
"SignKey",
|
||||
"-keyalg",
|
||||
"RSA",
|
||||
"-v",
|
||||
]
|
||||
)
|
||||
25
theseus_autopatcher/test.sh
Normal file
25
theseus_autopatcher/test.sh
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#!/usr/bin/bash
|
||||
|
||||
FOLDER=$(dirname "$(realpath $0)")
|
||||
|
||||
if adb devices | grep -q 'emulator-'; then
|
||||
echo 'Emulator already started'
|
||||
else
|
||||
echo 'Emulator no started'
|
||||
QT_QPA_PLATFORM=xcb alacritty -e ~/Android/Sdk/emulator/emulator -avd root34 &
|
||||
fi
|
||||
|
||||
env --chdir "${FOLDER}" poetry build
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
python -m venv "${TMP}"
|
||||
source "${TMP}/bin/activate"
|
||||
pip install "${FOLDER}/dist/theseus_autopatcher-0.1.0-py3-none-any.whl"
|
||||
|
||||
#source .venv/bin/activate
|
||||
|
||||
adb wait-for-device
|
||||
|
||||
theseus-autopatch -a "${FOLDER}/../test_apks/dynloading/build/test_dynloading.apk" -o /tmp/patched_dynloading.apk -k "${FOLDER}/../test_apks/dynloading/ToyKey.keystore"
|
||||
|
||||
rm -rf "${TMP}"
|
||||
Loading…
Add table
Add a link
Reference in a new issue