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]]
|
[[package]]
|
||||||
name = "alembic"
|
name = "alembic"
|
||||||
|
|
@ -18,7 +18,7 @@ SQLAlchemy = ">=1.3.0"
|
||||||
typing-extensions = ">=4"
|
typing-extensions = ">=4"
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
tz = ["backports.zoneinfo ; python_version < \"3.9\"", "tzdata"]
|
tz = ["backports.zoneinfo", "tzdata"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "androguard"
|
name = "androguard"
|
||||||
|
|
@ -132,6 +132,25 @@ files = [
|
||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
{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]]
|
[[package]]
|
||||||
name = "contourpy"
|
name = "contourpy"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
|
@ -267,7 +286,7 @@ files = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[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]]
|
[[package]]
|
||||||
name = "fonttools"
|
name = "fonttools"
|
||||||
|
|
@ -330,18 +349,18 @@ files = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[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)"]
|
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)"]
|
lxml = ["lxml (>=4.0)"]
|
||||||
pathops = ["skia-pathops (>=0.5.0)"]
|
pathops = ["skia-pathops (>=0.5.0)"]
|
||||||
plot = ["matplotlib"]
|
plot = ["matplotlib"]
|
||||||
repacker = ["uharfbuzz (>=0.23.0)"]
|
repacker = ["uharfbuzz (>=0.23.0)"]
|
||||||
symfont = ["sympy"]
|
symfont = ["sympy"]
|
||||||
type1 = ["xattr ; sys_platform == \"darwin\""]
|
type1 = ["xattr"]
|
||||||
ufo = ["fs (>=2.2.0,<3)"]
|
ufo = ["fs (>=2.2.0,<3)"]
|
||||||
unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""]
|
unicode = ["unicodedata2 (>=15.1.0)"]
|
||||||
woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"]
|
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frida"
|
name = "frida"
|
||||||
|
|
@ -472,6 +491,44 @@ files = [
|
||||||
docs = ["Sphinx", "furo"]
|
docs = ["Sphinx", "furo"]
|
||||||
test = ["objgraph", "psutil"]
|
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]]
|
[[package]]
|
||||||
name = "ipython"
|
name = "ipython"
|
||||||
version = "8.32.0"
|
version = "8.32.0"
|
||||||
|
|
@ -498,7 +555,7 @@ traitlets = ">=5.13.0"
|
||||||
[package.extras]
|
[package.extras]
|
||||||
all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"]
|
all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"]
|
||||||
black = ["black"]
|
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"]
|
kernel = ["ipykernel"]
|
||||||
matplotlib = ["matplotlib"]
|
matplotlib = ["matplotlib"]
|
||||||
nbconvert = ["nbconvert"]
|
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\""}
|
win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
|
||||||
|
|
||||||
[package.extras]
|
[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]]
|
[[package]]
|
||||||
name = "lxml"
|
name = "lxml"
|
||||||
|
|
@ -1213,7 +1270,7 @@ docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline
|
||||||
fpx = ["olefile"]
|
fpx = ["olefile"]
|
||||||
mic = ["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)"]
|
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"]
|
xmp = ["defusedxml"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1309,6 +1366,22 @@ files = [
|
||||||
[package.extras]
|
[package.extras]
|
||||||
diagrams = ["jinja2", "railroad-diagrams"]
|
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]]
|
[[package]]
|
||||||
name = "python-dateutil"
|
name = "python-dateutil"
|
||||||
version = "2.9.0.post0"
|
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\")"}
|
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]
|
[package.extras]
|
||||||
aiomysql = ["aiomysql (>=0.2.0) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
|
||||||
aiosqlite = ["aiosqlite ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\"", "typing_extensions (!=3.10.0.1)"]
|
aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
|
||||||
asyncio = ["greenlet (!=0.4.17) ; python_version >= \"3\""]
|
asyncio = ["greenlet (!=0.4.17)"]
|
||||||
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"]
|
||||||
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2) ; python_version >= \"3\"", "mariadb (>=1.0.1,!=1.1.2) ; python_version >= \"3\""]
|
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)", "mariadb (>=1.0.1,!=1.1.2)"]
|
||||||
mssql = ["pyodbc"]
|
mssql = ["pyodbc"]
|
||||||
mssql-pymssql = ["pymssql", "pymssql"]
|
mssql-pymssql = ["pymssql", "pymssql"]
|
||||||
mssql-pyodbc = ["pyodbc", "pyodbc"]
|
mssql-pyodbc = ["pyodbc", "pyodbc"]
|
||||||
mypy = ["mypy (>=0.910) ; python_version >= \"3\"", "sqlalchemy2-stubs"]
|
mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"]
|
||||||
mysql = ["mysqlclient (>=1.4.0) ; python_version >= \"3\"", "mysqlclient (>=1.4.0,<2) ; python_version < \"3\""]
|
mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"]
|
||||||
mysql-connector = ["mysql-connector-python", "mysql-connector-python"]
|
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 = ["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-asyncpg = ["asyncpg", "asyncpg", "greenlet (!=0.4.17)", "greenlet (!=0.4.17)"]
|
||||||
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0) ; python_version >= \"3\"", "pg8000 (>=1.16.6,!=1.29.0) ; python_version >= \"3\""]
|
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)", "pg8000 (>=1.16.6,!=1.29.0)"]
|
||||||
postgresql-psycopg2binary = ["psycopg2-binary"]
|
postgresql-psycopg2binary = ["psycopg2-binary"]
|
||||||
postgresql-psycopg2cffi = ["psycopg2cffi"]
|
postgresql-psycopg2cffi = ["psycopg2cffi"]
|
||||||
pymysql = ["pymysql (<1) ; python_version < \"3\"", "pymysql ; python_version >= \"3\""]
|
pymysql = ["pymysql", "pymysql (<1)"]
|
||||||
sqlcipher = ["sqlcipher3_binary ; python_version >= \"3\""]
|
sqlcipher = ["sqlcipher3_binary"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stack-data"
|
name = "stack-data"
|
||||||
|
|
@ -1525,6 +1598,40 @@ files = [
|
||||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
{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]]
|
[[package]]
|
||||||
name = "wcwidth"
|
name = "wcwidth"
|
||||||
version = "0.2.13"
|
version = "0.2.13"
|
||||||
|
|
@ -1647,9 +1754,12 @@ files = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[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]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = ">=3.13,<4.0.0"
|
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]
|
[build-system]
|
||||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
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"
|
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 != "":
|
if device_name != "":
|
||||||
device = frida.get_device(device_name)
|
device = frida.get_device(device_name)
|
||||||
env["ANDROID_SERIAL"] = 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
|
# Start server
|
||||||
proc: subprocess.CompletedProcess[str] | subprocess.CompletedProcess[bytes] = (
|
proc: subprocess.CompletedProcess[str] | subprocess.CompletedProcess[bytes] = (
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
["adb", "shell", "whoami"],
|
[adb, "shell", "whoami"],
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
env=env,
|
env=env,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if proc.stdout.strip() != "root":
|
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
|
# Rooting adb will disconnect the device
|
||||||
if device_name != "":
|
if device_name != "":
|
||||||
device = frida.get_device(device_name)
|
device = frida.get_device(device_name)
|
||||||
else:
|
else:
|
||||||
device = frida.get_usb_device()
|
device = frida.get_usb_device()
|
||||||
perm = subprocess.run(
|
perm = subprocess.run(
|
||||||
["adb", "shell", "stat", "-c", "%a", FRIDA_SERVER_ANDROID_PATH],
|
[adb, "shell", "stat", "-c", "%a", FRIDA_SERVER_ANDROID_PATH],
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
stderr=subprocess.PIPE,
|
stderr=subprocess.PIPE,
|
||||||
|
|
@ -287,7 +287,7 @@ def setup_frida(device_name: str, env: dict[str, str]) -> frida.core.Device:
|
||||||
|
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
[
|
[
|
||||||
"adb",
|
adb,
|
||||||
"push",
|
"push",
|
||||||
str((tmpd / "frida-server").absolute()),
|
str((tmpd / "frida-server").absolute()),
|
||||||
FRIDA_SERVER_ANDROID_PATH,
|
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:
|
if need_perm_resset:
|
||||||
subprocess.run(
|
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
|
# The server take some time to start
|
||||||
# time.sleep(3)
|
# time.sleep(3)
|
||||||
t = spinner()
|
t = spinner()
|
||||||
|
|
@ -313,23 +313,39 @@ def setup_frida(device_name: str, env: dict[str, str]) -> frida.core.Device:
|
||||||
time.sleep(0.3)
|
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)
|
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():
|
if not file_storage.exists():
|
||||||
file_storage.mkdir(parents=True)
|
file_storage.mkdir(parents=True)
|
||||||
if not file_storage.is_dir():
|
if not file_storage.is_dir():
|
||||||
print("[!] file_storage must be a directory")
|
print("[!] file_storage must be a directory")
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
device = setup_frida(device_name, env)
|
device = setup_frida(device_name, env, adb)
|
||||||
|
|
||||||
app = get_apkid(apk)[0]
|
app = get_apkid(apk)[0]
|
||||||
|
|
||||||
if device.enumerate_applications([app]):
|
if device.enumerate_applications([app]):
|
||||||
# Uninstall the APK if it already exist
|
# Uninstall the APK if it already exist
|
||||||
subprocess.run(["adb", "uninstall", app], env=env)
|
subprocess.run([adb, "uninstall", app], env=env)
|
||||||
subprocess.run(["adb", "install", str(apk.absolute())], env=env)
|
subprocess.run([adb, "install", str(apk.absolute())], env=env)
|
||||||
|
|
||||||
with FRIDA_SCRIPT.open("r") as file:
|
with FRIDA_SCRIPT.open("r") as file:
|
||||||
jsscript = file.read()
|
jsscript = file.read()
|
||||||
|
|
@ -380,7 +396,7 @@ def collect_runtime(apk: Path, device_name: str, file_storage: Path, output: Tex
|
||||||
# time.sleep(0.3)
|
# time.sleep(0.3)
|
||||||
# print(f"[*] Classloader list received" + " " * 20)
|
# 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
|
# Try to find the Main class loader
|
||||||
main_class_loader: str | None = None
|
main_class_loader: str | None = None
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,28 @@
|
||||||
def explore_app():
|
from pathlib import Path
|
||||||
manual_exploration()
|
|
||||||
|
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():
|
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]]
|
[[package]]
|
||||||
name = "alembic"
|
name = "alembic"
|
||||||
|
|
@ -213,6 +213,24 @@ files = [
|
||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
{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]]
|
[[package]]
|
||||||
name = "contourpy"
|
name = "contourpy"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
|
|
@ -336,10 +354,10 @@ files = [
|
||||||
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
|
cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""}
|
||||||
|
|
||||||
[package.extras]
|
[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)"]
|
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\""]
|
nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2)"]
|
||||||
pep8test = ["check-sdist ; python_version >= \"3.8\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"]
|
pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"]
|
||||||
sdist = ["build (>=1.0.0)"]
|
sdist = ["build (>=1.0.0)"]
|
||||||
ssh = ["bcrypt (>=3.1.5)"]
|
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)"]
|
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]
|
[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]]
|
[[package]]
|
||||||
name = "fonttools"
|
name = "fonttools"
|
||||||
|
|
@ -469,18 +487,18 @@ files = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[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)"]
|
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)"]
|
lxml = ["lxml (>=4.0)"]
|
||||||
pathops = ["skia-pathops (>=0.5.0)"]
|
pathops = ["skia-pathops (>=0.5.0)"]
|
||||||
plot = ["matplotlib"]
|
plot = ["matplotlib"]
|
||||||
repacker = ["uharfbuzz (>=0.23.0)"]
|
repacker = ["uharfbuzz (>=0.23.0)"]
|
||||||
symfont = ["sympy"]
|
symfont = ["sympy"]
|
||||||
type1 = ["xattr ; sys_platform == \"darwin\""]
|
type1 = ["xattr"]
|
||||||
ufo = ["fs (>=2.2.0,<3)"]
|
ufo = ["fs (>=2.2.0,<3)"]
|
||||||
unicode = ["unicodedata2 (>=15.1.0) ; python_version <= \"3.12\""]
|
unicode = ["unicodedata2 (>=15.1.0)"]
|
||||||
woff = ["brotli (>=1.0.1) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\"", "zopfli (>=0.1.4)"]
|
woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "frida"
|
name = "frida"
|
||||||
|
|
@ -611,6 +629,42 @@ files = [
|
||||||
docs = ["Sphinx", "furo"]
|
docs = ["Sphinx", "furo"]
|
||||||
test = ["objgraph", "psutil"]
|
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]]
|
[[package]]
|
||||||
name = "ipython"
|
name = "ipython"
|
||||||
version = "9.0.2"
|
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\""}
|
win32-setctime = {version = ">=1.0.0", markers = "sys_platform == \"win32\""}
|
||||||
|
|
||||||
[package.extras]
|
[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]]
|
[[package]]
|
||||||
name = "lxml"
|
name = "lxml"
|
||||||
|
|
@ -1347,7 +1401,7 @@ docs = ["furo", "olefile", "sphinx (>=8.1)", "sphinx-copybutton", "sphinx-inline
|
||||||
fpx = ["olefile"]
|
fpx = ["olefile"]
|
||||||
mic = ["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)"]
|
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"]
|
xmp = ["defusedxml"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1456,6 +1510,22 @@ files = [
|
||||||
[package.extras]
|
[package.extras]
|
||||||
diagrams = ["jinja2", "railroad-diagrams"]
|
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]]
|
[[package]]
|
||||||
name = "python-dateutil"
|
name = "python-dateutil"
|
||||||
version = "2.9.0.post0"
|
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\")"}
|
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]
|
[package.extras]
|
||||||
aiomysql = ["aiomysql (>=0.2.0) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
aiomysql = ["aiomysql (>=0.2.0)", "greenlet (!=0.4.17)"]
|
||||||
aiosqlite = ["aiosqlite ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\"", "typing_extensions (!=3.10.0.1)"]
|
aiosqlite = ["aiosqlite", "greenlet (!=0.4.17)", "typing_extensions (!=3.10.0.1)"]
|
||||||
asyncio = ["greenlet (!=0.4.17) ; python_version >= \"3\""]
|
asyncio = ["greenlet (!=0.4.17)"]
|
||||||
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4) ; python_version >= \"3\"", "greenlet (!=0.4.17) ; python_version >= \"3\""]
|
asyncmy = ["asyncmy (>=0.2.3,!=0.2.4)", "greenlet (!=0.4.17)"]
|
||||||
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2) ; python_version >= \"3\"", "mariadb (>=1.0.1,!=1.1.2) ; python_version >= \"3\""]
|
mariadb-connector = ["mariadb (>=1.0.1,!=1.1.2)", "mariadb (>=1.0.1,!=1.1.2)"]
|
||||||
mssql = ["pyodbc"]
|
mssql = ["pyodbc"]
|
||||||
mssql-pymssql = ["pymssql", "pymssql"]
|
mssql-pymssql = ["pymssql", "pymssql"]
|
||||||
mssql-pyodbc = ["pyodbc", "pyodbc"]
|
mssql-pyodbc = ["pyodbc", "pyodbc"]
|
||||||
mypy = ["mypy (>=0.910) ; python_version >= \"3\"", "sqlalchemy2-stubs"]
|
mypy = ["mypy (>=0.910)", "sqlalchemy2-stubs"]
|
||||||
mysql = ["mysqlclient (>=1.4.0) ; python_version >= \"3\"", "mysqlclient (>=1.4.0,<2) ; python_version < \"3\""]
|
mysql = ["mysqlclient (>=1.4.0)", "mysqlclient (>=1.4.0,<2)"]
|
||||||
mysql-connector = ["mysql-connector-python", "mysql-connector-python"]
|
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 = ["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-asyncpg = ["asyncpg", "asyncpg", "greenlet (!=0.4.17)", "greenlet (!=0.4.17)"]
|
||||||
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0) ; python_version >= \"3\"", "pg8000 (>=1.16.6,!=1.29.0) ; python_version >= \"3\""]
|
postgresql-pg8000 = ["pg8000 (>=1.16.6,!=1.29.0)", "pg8000 (>=1.16.6,!=1.29.0)"]
|
||||||
postgresql-psycopg2binary = ["psycopg2-binary"]
|
postgresql-psycopg2binary = ["psycopg2-binary"]
|
||||||
postgresql-psycopg2cffi = ["psycopg2cffi"]
|
postgresql-psycopg2cffi = ["psycopg2cffi"]
|
||||||
pymysql = ["pymysql (<1) ; python_version < \"3\"", "pymysql ; python_version >= \"3\""]
|
pymysql = ["pymysql", "pymysql (<1)"]
|
||||||
sqlcipher = ["sqlcipher3_binary ; python_version >= \"3\""]
|
sqlcipher = ["sqlcipher3_binary"]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stack-data"
|
name = "stack-data"
|
||||||
|
|
@ -1691,6 +1761,38 @@ files = [
|
||||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
{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]]
|
[[package]]
|
||||||
name = "wcwidth"
|
name = "wcwidth"
|
||||||
version = "0.2.13"
|
version = "0.2.13"
|
||||||
|
|
@ -1813,9 +1915,9 @@ files = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[package.extras]
|
[package.extras]
|
||||||
dev = ["black (>=19.3b0) ; python_version >= \"3.6\"", "pytest (>=4.6.2)"]
|
dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"]
|
||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.1"
|
lock-version = "2.1"
|
||||||
python-versions = ">=3.13,<4.0.0"
|
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]
|
[tool.poetry.dependencies]
|
||||||
theseus-frida = { path = "../frida" }
|
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]
|
[tool.poetry]
|
||||||
packages = [{include = "theseus_autopatcher", from = "src"}]
|
packages = [{include = "theseus_autopatcher", from = "src"}]
|
||||||
|
|
|
||||||
|
|
@ -7,87 +7,7 @@ from shutil import which
|
||||||
|
|
||||||
from theseus_frida import collect_runtime
|
from theseus_frida import collect_runtime
|
||||||
|
|
||||||
|
from .utils import *
|
||||||
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",
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
PATCHER_BIN_PATH = Path(__file__).parent / "patcher_86_64_musl"
|
PATCHER_BIN_PATH = Path(__file__).parent / "patcher_86_64_musl"
|
||||||
|
|
||||||
|
|
@ -100,30 +20,24 @@ def patch_apk(
|
||||||
apksigner: Path,
|
apksigner: Path,
|
||||||
keystore: Path,
|
keystore: Path,
|
||||||
):
|
):
|
||||||
def dbg(l):
|
|
||||||
print(" ".join(l))
|
|
||||||
return l
|
|
||||||
|
|
||||||
subprocess.run(
|
subprocess.run(
|
||||||
dbg(
|
[
|
||||||
[
|
str(PATCHER_BIN_PATH.absolute()),
|
||||||
str(PATCHER_BIN_PATH.absolute()),
|
"--runtime-data",
|
||||||
"--runtime-data",
|
str(runtime_data.absolute()),
|
||||||
str(runtime_data.absolute()),
|
"--path",
|
||||||
"--path",
|
str(apk.absolute()),
|
||||||
str(apk.absolute()),
|
"--out",
|
||||||
"--out",
|
str(apkout.absolute()),
|
||||||
str(apkout.absolute()),
|
"-k",
|
||||||
"-k",
|
str(keystore.absolute()),
|
||||||
str(keystore.absolute()),
|
"-z",
|
||||||
"-z",
|
str(zipalign.absolute()),
|
||||||
str(zipalign.absolute()),
|
"-a",
|
||||||
"-a",
|
str(apksigner.absolute()),
|
||||||
str(apksigner.absolute()),
|
"--code-loading-patch-strategy",
|
||||||
"--code-loading-patch-strategy",
|
"model-class-loaders",
|
||||||
"model-class-loaders",
|
]
|
||||||
]
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -228,6 +142,7 @@ def main():
|
||||||
device_name=args.device,
|
device_name=args.device,
|
||||||
file_storage=tmpd / "dex",
|
file_storage=tmpd / "dex",
|
||||||
output=fp,
|
output=fp,
|
||||||
|
android_sdk_path=get_android_sdk_path(),
|
||||||
)
|
)
|
||||||
patch_apk(
|
patch_apk(
|
||||||
runtime_data=tmpd / "runtime.json",
|
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