trueseeing 2.2.7__tar.gz → 2.2.8__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trueseeing-2.2.8/.dockerignore +4 -0
- trueseeing-2.2.8/.github/workflows/lint.yaml +27 -0
- trueseeing-2.2.8/Dockerfile +24 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/PKG-INFO +30 -18
- {trueseeing-2.2.7 → trueseeing-2.2.8}/README.md +18 -2
- {trueseeing-2.2.7 → trueseeing-2.2.8}/pyproject.toml +20 -18
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/__init__.py +1 -1
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/android/engage.py +40 -17
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/android/recon.py +11 -11
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/ios/engage.py +24 -12
- trueseeing-2.2.8/trueseeing/app/cmd/ios/recon.py +53 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/inspect.py +1 -1
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/asm.py +55 -1
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/device.py +6 -6
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/env.py +6 -2
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ios/device.py +21 -21
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/nat.py +1 -1
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/tools.py +2 -2
- trueseeing-2.2.8/uv.lock +1927 -0
- trueseeing-2.2.7/.dockerignore +0 -3
- trueseeing-2.2.7/.github/workflows/lint.yaml +0 -25
- trueseeing-2.2.7/Dockerfile +0 -25
- {trueseeing-2.2.7 → trueseeing-2.2.8}/.github/FUNDING.yml +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/.github/workflows/deploy.yaml +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/.github/workflows/publish.yaml +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/.github/workflows/stale.yaml +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/.gitignore +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/COPYING +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/api.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/alias.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/analyze.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/android/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/android/asm.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/android/search.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/android/show.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/config.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/info.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/ios/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/report.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/scan.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/search.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/cmd/show.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/scan.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/app/shell.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/analyze.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/analyze/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/analyze/flow.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/analyze/nat.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/analyze/op.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/context.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/db.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/model.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/store.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/android/tools.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/config.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/context.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/cvss.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/db.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/exc.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ext.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ios/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ios/analyze.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ios/context.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ios/db.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ios/model.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ios/store.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ios/swift.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/model/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/model/cmd.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/model/issue.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/model/sig.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/report.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/scan.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/store.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/ui.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/core/z.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/LICENSE.md +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/android/abe.jar +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/android/apkeditor.jar +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/android/apksigner.jar +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/android/frida-app.smali +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/android/frida-scriptdir.config +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/android/nsc.xml +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/android/store.0.sql +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/android/store.1.sql +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/files.0.sql +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/ios/store.0.sql +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/ios/store.1.sql +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/public_suffix_list.dat +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/store.0.sql +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/store.s.sql +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/template/report.html +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/libs/tlds.txt +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/py.typed +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/android/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/android/crypto.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/android/fingerprint.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/android/manifest.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/android/nat.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/android/privacy.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/android/security.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/ios/__init__.py +0 -0
- {trueseeing-2.2.7 → trueseeing-2.2.8}/trueseeing/sig/ios/base.py +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: lint
|
|
2
|
+
|
|
3
|
+
on: push
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
lint:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
steps:
|
|
9
|
+
- name: Check out code
|
|
10
|
+
uses: actions/checkout@v3
|
|
11
|
+
|
|
12
|
+
- name: Install uv
|
|
13
|
+
uses: astral-sh/setup-uv@v6
|
|
14
|
+
with:
|
|
15
|
+
version: "0.8.22"
|
|
16
|
+
enable-cache: false
|
|
17
|
+
|
|
18
|
+
- name: Install Python
|
|
19
|
+
run: uv python install
|
|
20
|
+
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: uv sync --locked --dev
|
|
23
|
+
|
|
24
|
+
- name: Analysing the code
|
|
25
|
+
run: |
|
|
26
|
+
uv run mypy trueseeing
|
|
27
|
+
uv run pflake8 --color=never trueseeing
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
from python:3.13-slim-bookworm
|
|
2
|
+
run apt-get update -y
|
|
3
|
+
run apt-get install -y --no-install-recommends git
|
|
4
|
+
run pip install --no-cache-dir uv
|
|
5
|
+
copy . /usr/lib/ts2
|
|
6
|
+
run bash -c "cd /usr/lib/ts2 && uv sync --active --locked --no-dev"
|
|
7
|
+
run (cd /usr/lib && git clone https://github.com/alterakey/ts2-frida-ios-dump.git frida-ios-dump && cd frida-ios-dump && uv venv && uv pip install -r ./requirements.txt)
|
|
8
|
+
|
|
9
|
+
from python:3.13-slim-bookworm
|
|
10
|
+
run apt-get update -y
|
|
11
|
+
run apt-get install -y --no-install-recommends openjdk-17-jre-headless zip adb && rm -rf /var/lib/apt/lists/*
|
|
12
|
+
run install -d -m 777 /data /ext /cache /out && ln -sfn /cache /root/.local
|
|
13
|
+
copy --from=0 /usr/lib/frida-ios-dump /usr/lib/frida-ios-dump
|
|
14
|
+
copy --from=0 /usr/lib/ts2 /usr/lib/ts2
|
|
15
|
+
env PATH=/usr/lib/ts2/.venv/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
|
|
16
|
+
env TS2_IN_DOCKER=1
|
|
17
|
+
env TS2_CACHEDIR=/cache
|
|
18
|
+
env TS2_HOME=/data
|
|
19
|
+
env TS2_EXTDIR=/ext
|
|
20
|
+
env TS2_FRIDA_IOS_DUMP_PATH=/usr/lib/frida-ios-dump/dump.py
|
|
21
|
+
env TS2_FRIDA_IOS_DUMP_INTERP=/usr/lib/frida-ios-dump/.venv/bin/python3
|
|
22
|
+
env TS2_SWIFT_DEMANGLER_URL=http://ts2-swift-demangle
|
|
23
|
+
workdir /out
|
|
24
|
+
entrypoint ["trueseeing"]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: trueseeing
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.8
|
|
4
4
|
Summary: Trueseeing is a non-decompiling iOS/Android application vulnerability scanner.
|
|
5
5
|
Keywords: ios,android,security,pentest,hacking
|
|
6
6
|
Author-email: Takahiro Yoshimura <alterakey@protonmail.com>
|
|
@@ -14,25 +14,21 @@ Classifier: Operating System :: MacOS :: MacOS X
|
|
|
14
14
|
Classifier: Operating System :: Android
|
|
15
15
|
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
|
|
16
16
|
License-File: COPYING
|
|
17
|
-
Requires-Dist: lxml~=5.0
|
|
18
|
-
Requires-Dist: pyyaml~=6.0
|
|
19
|
-
Requires-Dist: jinja2~=3.1
|
|
20
|
-
Requires-Dist: pypubsub~=4.0
|
|
21
|
-
Requires-Dist: termcolor~=2.4
|
|
22
|
-
Requires-Dist: progressbar2~=4.3
|
|
23
|
-
Requires-Dist: importlib_metadata~=7.0
|
|
24
|
-
Requires-Dist: asn1crypto~=1.5
|
|
25
|
-
Requires-Dist: pyzstd~=0.16
|
|
26
17
|
Requires-Dist: aiohttp~=3.9
|
|
18
|
+
Requires-Dist: asn1crypto~=1.5
|
|
19
|
+
Requires-Dist: frida-tools~=13.6
|
|
20
|
+
Requires-Dist: importlib-metadata~=7.0
|
|
21
|
+
Requires-Dist: jinja2~=3.1
|
|
27
22
|
Requires-Dist: lief~=0.14
|
|
28
|
-
Requires-Dist:
|
|
23
|
+
Requires-Dist: lxml~=5.0
|
|
24
|
+
Requires-Dist: progressbar2~=4.3
|
|
29
25
|
Requires-Dist: prompt-toolkit~=3.0
|
|
30
|
-
Requires-Dist:
|
|
31
|
-
Requires-Dist:
|
|
32
|
-
Requires-Dist:
|
|
33
|
-
Requires-Dist:
|
|
26
|
+
Requires-Dist: pyaxmlparser~=0.3
|
|
27
|
+
Requires-Dist: pypubsub~=4.0
|
|
28
|
+
Requires-Dist: pyyaml~=6.0
|
|
29
|
+
Requires-Dist: pyzstd~=0.16
|
|
30
|
+
Requires-Dist: termcolor~=2.4
|
|
34
31
|
Project-URL: Source, https://github.com/alterakey/trueseeing
|
|
35
|
-
Provides-Extra: dev
|
|
36
32
|
|
|
37
33
|
# README
|
|
38
34
|
|
|
@@ -77,13 +73,18 @@ If you want to run statelessly you omit mounting volume onto /cache (not recomme
|
|
|
77
73
|
$ docker run --rm -v $(pwd):/out ghcr.io/alterakey/trueseeing
|
|
78
74
|
|
|
79
75
|
|
|
80
|
-
### With pip
|
|
76
|
+
### With pip / uvx
|
|
81
77
|
|
|
82
78
|
Alternatively, you can install our package with pip as follows. This form of installation might be useful for extensions, as it grants them the greatest freedom. Just remember you need a JRE and Android SDK (optionally; to mess with devices):
|
|
83
79
|
|
|
84
80
|
$ pip install --user trueseeing
|
|
85
81
|
$ trueseeing
|
|
86
82
|
|
|
83
|
+
Or, with [uv](https://github.com/astral-sh/uv) you could do:
|
|
84
|
+
|
|
85
|
+
$ uvx trueseeing
|
|
86
|
+
|
|
87
|
+
|
|
87
88
|
## Usage
|
|
88
89
|
|
|
89
90
|
### Interactive mode
|
|
@@ -91,7 +92,7 @@ Alternatively, you can install our package with pip as follows. This form of ins
|
|
|
91
92
|
You can interactively scan/analyze/patch/etc. apps -- making it the ideal choice for manual analysis:
|
|
92
93
|
|
|
93
94
|
$ trueseeing target.apk
|
|
94
|
-
[+] trueseeing 2.2.
|
|
95
|
+
[+] trueseeing 2.2.8
|
|
95
96
|
ts[target.apk]> ?
|
|
96
97
|
...
|
|
97
98
|
ts[target.apk]> i # show generic information
|
|
@@ -179,6 +180,17 @@ To hack it, you need to create a proper build environment. To create one, set up
|
|
|
179
180
|
(.venv) $ flit build # to build (wheel)
|
|
180
181
|
(.venv) $ docker build -t trueseeing . # to build (container)
|
|
181
182
|
|
|
183
|
+
Or, with [uv](https://github.com/astral-sh/uv) you could do:
|
|
184
|
+
|
|
185
|
+
$ git clone https://github.com/alterakey/trueseeing.git wc
|
|
186
|
+
$ uv sync --locked
|
|
187
|
+
$ (... hack ...)
|
|
188
|
+
$ uv run trueseeing ... # to run
|
|
189
|
+
$ uv run mypy trueseeing && uv run pflake8 trueseeing # to validate
|
|
190
|
+
Success: no issues found in XX source files
|
|
191
|
+
$ uv run flit build # to build (wheel)
|
|
192
|
+
$ docker build -t trueseeing . # to build (container)
|
|
193
|
+
|
|
182
194
|
|
|
183
195
|
## Details
|
|
184
196
|
|
|
@@ -41,13 +41,18 @@ If you want to run statelessly you omit mounting volume onto /cache (not recomme
|
|
|
41
41
|
$ docker run --rm -v $(pwd):/out ghcr.io/alterakey/trueseeing
|
|
42
42
|
|
|
43
43
|
|
|
44
|
-
### With pip
|
|
44
|
+
### With pip / uvx
|
|
45
45
|
|
|
46
46
|
Alternatively, you can install our package with pip as follows. This form of installation might be useful for extensions, as it grants them the greatest freedom. Just remember you need a JRE and Android SDK (optionally; to mess with devices):
|
|
47
47
|
|
|
48
48
|
$ pip install --user trueseeing
|
|
49
49
|
$ trueseeing
|
|
50
50
|
|
|
51
|
+
Or, with [uv](https://github.com/astral-sh/uv) you could do:
|
|
52
|
+
|
|
53
|
+
$ uvx trueseeing
|
|
54
|
+
|
|
55
|
+
|
|
51
56
|
## Usage
|
|
52
57
|
|
|
53
58
|
### Interactive mode
|
|
@@ -55,7 +60,7 @@ Alternatively, you can install our package with pip as follows. This form of ins
|
|
|
55
60
|
You can interactively scan/analyze/patch/etc. apps -- making it the ideal choice for manual analysis:
|
|
56
61
|
|
|
57
62
|
$ trueseeing target.apk
|
|
58
|
-
[+] trueseeing 2.2.
|
|
63
|
+
[+] trueseeing 2.2.8
|
|
59
64
|
ts[target.apk]> ?
|
|
60
65
|
...
|
|
61
66
|
ts[target.apk]> i # show generic information
|
|
@@ -143,6 +148,17 @@ To hack it, you need to create a proper build environment. To create one, set up
|
|
|
143
148
|
(.venv) $ flit build # to build (wheel)
|
|
144
149
|
(.venv) $ docker build -t trueseeing . # to build (container)
|
|
145
150
|
|
|
151
|
+
Or, with [uv](https://github.com/astral-sh/uv) you could do:
|
|
152
|
+
|
|
153
|
+
$ git clone https://github.com/alterakey/trueseeing.git wc
|
|
154
|
+
$ uv sync --locked
|
|
155
|
+
$ (... hack ...)
|
|
156
|
+
$ uv run trueseeing ... # to run
|
|
157
|
+
$ uv run mypy trueseeing && uv run pflake8 trueseeing # to validate
|
|
158
|
+
Success: no issues found in XX source files
|
|
159
|
+
$ uv run flit build # to build (wheel)
|
|
160
|
+
$ docker build -t trueseeing . # to build (container)
|
|
161
|
+
|
|
146
162
|
|
|
147
163
|
## Details
|
|
148
164
|
|
|
@@ -19,31 +19,24 @@ classifiers = [
|
|
|
19
19
|
readme = "README.md"
|
|
20
20
|
keywords = ['ios', 'android', 'security', 'pentest', 'hacking']
|
|
21
21
|
dependencies = [
|
|
22
|
-
"lxml~=5.0",
|
|
23
|
-
"pyyaml~=6.0",
|
|
24
|
-
"jinja2~=3.1",
|
|
25
|
-
"pypubsub~=4.0",
|
|
26
|
-
"termcolor~=2.4",
|
|
27
|
-
"progressbar2~=4.3",
|
|
28
|
-
"importlib_metadata~=7.0",
|
|
29
|
-
"asn1crypto~=1.5",
|
|
30
|
-
"pyzstd~=0.16",
|
|
31
22
|
"aiohttp~=3.9",
|
|
23
|
+
"asn1crypto~=1.5",
|
|
24
|
+
"frida-tools~=13.6",
|
|
25
|
+
"importlib-metadata~=7.0",
|
|
26
|
+
"jinja2~=3.1",
|
|
32
27
|
"lief~=0.14",
|
|
33
|
-
"
|
|
28
|
+
"lxml~=5.0",
|
|
29
|
+
"progressbar2~=4.3",
|
|
34
30
|
"prompt-toolkit~=3.0",
|
|
35
|
-
|
|
31
|
+
"pyaxmlparser~=0.3",
|
|
32
|
+
"pypubsub~=4.0",
|
|
33
|
+
"pyyaml~=6.0",
|
|
34
|
+
"pyzstd~=0.16",
|
|
35
|
+
"termcolor~=2.4",
|
|
36
36
|
]
|
|
37
37
|
requires-python = ">=3.9"
|
|
38
38
|
dynamic = ['version', 'description']
|
|
39
39
|
|
|
40
|
-
[project.optional-dependencies]
|
|
41
|
-
dev = [
|
|
42
|
-
"mypy~=1.13",
|
|
43
|
-
"pyproject-flake8~=7.0",
|
|
44
|
-
"typing_extensions~=4.12",
|
|
45
|
-
]
|
|
46
|
-
|
|
47
40
|
[project.urls]
|
|
48
41
|
Source = "https://github.com/alterakey/trueseeing"
|
|
49
42
|
|
|
@@ -69,3 +62,12 @@ ignore_missing_imports = true
|
|
|
69
62
|
[tool.flake8]
|
|
70
63
|
extend-ignore = "E301,E302,E265,E114,E501,E231,E252,E261,E701,E722,E741"
|
|
71
64
|
indent-size = 2
|
|
65
|
+
|
|
66
|
+
[dependency-groups]
|
|
67
|
+
dev = [
|
|
68
|
+
"flit>=3.12.0",
|
|
69
|
+
"mypy~=1.13",
|
|
70
|
+
"pyproject-flake8~=7.0",
|
|
71
|
+
"types-pygments>=2.19.0.20250809",
|
|
72
|
+
"typing_extensions~=4.12",
|
|
73
|
+
]
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""Trueseeing is a non-decompiling iOS/Android application vulnerability scanner."""
|
|
2
|
-
__version__ = '2.2.
|
|
2
|
+
__version__ = '2.2.8'
|
|
@@ -219,7 +219,7 @@ class EngageCommand(CommandMixin):
|
|
|
219
219
|
ui.info('enabling full backup {apk}'.format(apk=apk))
|
|
220
220
|
|
|
221
221
|
at = time.time()
|
|
222
|
-
context = await self._helper.get_context().require_type('apk').analyze(level=
|
|
222
|
+
context = await self._helper.get_context().require_type('apk').analyze(level=2)
|
|
223
223
|
with context.store().query().scoped() as q:
|
|
224
224
|
path = 'AndroidManifest.xml'
|
|
225
225
|
blob = q.file_get(path, patched=True)
|
|
@@ -868,6 +868,8 @@ class EngageCommand(CommandMixin):
|
|
|
868
868
|
context: APKContext = self._helper.get_context().require_type('apk')
|
|
869
869
|
apk = context.target
|
|
870
870
|
|
|
871
|
+
import os.path
|
|
872
|
+
from tempfile import TemporaryDirectory
|
|
871
873
|
from time import time
|
|
872
874
|
from shlex import quote
|
|
873
875
|
from pubsub import pub
|
|
@@ -888,25 +890,46 @@ class EngageCommand(CommandMixin):
|
|
|
888
890
|
if b'success' in l.lower():
|
|
889
891
|
ui.warn('removing existing package')
|
|
890
892
|
except CalledProcessError as e:
|
|
891
|
-
ui.
|
|
893
|
+
ui.warn('uninstalling appears to have failed (continuing anyway): {}'.format(e.stdout.decode().rstrip()))
|
|
892
894
|
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
async for l in dev.invoke_adb_streaming(f'install --no-streaming {quote(apk)}', redir_stderr=True):
|
|
897
|
-
pub.sendMessage('progress.android.adb.update')
|
|
898
|
-
if b'failure' in l.lower():
|
|
899
|
-
ui.stderr('')
|
|
900
|
-
if not cmd.endswith('!'):
|
|
901
|
-
ui.fatal('install failed; force (!) to replace ({})'.format(l.decode('UTF-8')))
|
|
902
|
-
else:
|
|
903
|
-
ui.fatal('install failed ({})'.format(l.decode('UTF-8')))
|
|
895
|
+
async def _do(apk: str, wd: str, *, in_retry: bool = False) -> None:
|
|
896
|
+
with AndroidInstallProgressReporter().scoped():
|
|
897
|
+
pub.sendMessage('progress.android.adb.begin', what='installing ... ')
|
|
904
898
|
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
899
|
+
if not apk.endswith('.xapk'):
|
|
900
|
+
cmd = f'install --no-streaming {quote(apk)}'
|
|
901
|
+
else:
|
|
902
|
+
from trueseeing.core.android.asm import APKDisassembler
|
|
903
|
+
slices = [s async for s in APKDisassembler.get_slices(apk, os.path.join(wd, 'slices'))]
|
|
904
|
+
cmd = ' '.join(['install-multiple', '--no-streaming'] + slices)
|
|
905
|
+
|
|
906
|
+
try:
|
|
907
|
+
async for l in dev.invoke_adb_streaming(cmd, redir_stderr=True):
|
|
908
|
+
pub.sendMessage('progress.android.adb.update')
|
|
909
|
+
msg = l.lower()
|
|
910
|
+
if b'failure' in msg:
|
|
911
|
+
ui.stderr('')
|
|
912
|
+
|
|
913
|
+
if b'signature' in msg and not in_retry: # XXX
|
|
914
|
+
ui.warn('package signature seems to be broken: re-signing')
|
|
915
|
+
with TemporaryDirectory(dir=wd) as td:
|
|
916
|
+
from trueseeing.core.android.asm import APKSigner
|
|
917
|
+
apk, _ = await APKSigner().sign(apk, td)
|
|
918
|
+
return await _do(apk, td, in_retry=True)
|
|
919
|
+
|
|
920
|
+
if not cmd.endswith('!'):
|
|
921
|
+
ui.fatal('install failed; force (!) to replace ({})'.format(l.decode('UTF-8')))
|
|
922
|
+
else:
|
|
923
|
+
ui.fatal('install failed ({})'.format(l.decode('UTF-8')))
|
|
924
|
+
|
|
925
|
+
pub.sendMessage('progress.android.adb.done')
|
|
926
|
+
except CalledProcessError as e:
|
|
927
|
+
ui.fatal('install failed: {}'.format(e.stdout.decode().rstrip()))
|
|
928
|
+
|
|
929
|
+
with TemporaryDirectory() as td:
|
|
930
|
+
await _do(apk, td)
|
|
908
931
|
|
|
909
|
-
|
|
932
|
+
ui.success('done ({t:.02f} sec){trailer}'.format(t=time() - at, trailer=' '*8))
|
|
910
933
|
|
|
911
934
|
async def _engage_undeploy_package(self, args: deque[str]) -> None:
|
|
912
935
|
_ = args.popleft()
|
|
@@ -39,17 +39,17 @@ class ReconCommand(CommandMixin):
|
|
|
39
39
|
|
|
40
40
|
def get_commands(self) -> CommandMap:
|
|
41
41
|
return {
|
|
42
|
-
'!!':dict(e=self._recon_shell, n='!!', d='run shell on device'),
|
|
43
|
-
'rwl':dict(e=self._recon_watch_logcat, n='rwl[!] [pat]', d='recon: watch logcat (!: system-wide)'),
|
|
44
|
-
'rwl!':dict(e=self._recon_watch_logcat),
|
|
45
|
-
'rwf':dict(e=self._recon_watch_fs, n='rwf', d='recon: watch filesystem'),
|
|
46
|
-
'rwt':dict(e=self._recon_watch_intent, n='rwt[!] [pat]', d='recon: watch intent'),
|
|
47
|
-
'rwt!':dict(e=self._recon_watch_intent),
|
|
48
|
-
'rwu':dict(e=self._recon_watch_ui, n='rwu[!] [pat|xp:xpath] [output.xml]', d='recon: watch device UI'),
|
|
49
|
-
'rwu!':dict(e=self._recon_watch_ui),
|
|
50
|
-
'rwx':dict(e=self._recon_watch_start, n='rwx', d='recon: start watching'),
|
|
51
|
-
'rp':dict(e=self._recon_list_packages, n='rp', d='recon: list installed packages'),
|
|
52
|
-
'ru':dict(e=self._recon_dump_ui, n='ru [output.xml]', d='recon: dump device UI'),
|
|
42
|
+
'!!':dict(e=self._recon_shell, n='!!', d='run shell on device', t={'apk'}),
|
|
43
|
+
'rwl':dict(e=self._recon_watch_logcat, n='rwl[!] [pat]', d='recon: watch logcat (!: system-wide)', t={'apk'}),
|
|
44
|
+
'rwl!':dict(e=self._recon_watch_logcat, t={'apk'}),
|
|
45
|
+
'rwf':dict(e=self._recon_watch_fs, n='rwf', d='recon: watch filesystem', t={'apk'}),
|
|
46
|
+
'rwt':dict(e=self._recon_watch_intent, n='rwt[!] [pat]', d='recon: watch intent', t={'apk'}),
|
|
47
|
+
'rwt!':dict(e=self._recon_watch_intent, t={'apk'}),
|
|
48
|
+
'rwu':dict(e=self._recon_watch_ui, n='rwu[!] [pat|xp:xpath] [output.xml]', d='recon: watch device UI', t={'apk'}),
|
|
49
|
+
'rwu!':dict(e=self._recon_watch_ui, t={'apk'}),
|
|
50
|
+
'rwx':dict(e=self._recon_watch_start, n='rwx', d='recon: start watching', t={'apk'}),
|
|
51
|
+
'rp':dict(e=self._recon_list_packages, n='rp', d='recon: list installed packages', t={'apk'}),
|
|
52
|
+
'ru':dict(e=self._recon_dump_ui, n='ru [output.xml]', d='recon: dump device UI', t={'apk'}),
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
def _get_apk_context(self) -> APKContext:
|
|
@@ -8,7 +8,7 @@ from trueseeing.core.model.cmd import CommandMixin
|
|
|
8
8
|
from trueseeing.core.ui import ui
|
|
9
9
|
|
|
10
10
|
if TYPE_CHECKING:
|
|
11
|
-
from typing import Mapping, List
|
|
11
|
+
from typing import Mapping, List, Tuple
|
|
12
12
|
from trueseeing.api import CommandHelper, Command, CommandMap, OptionMap
|
|
13
13
|
from trueseeing.core.ios.context import IPAContext
|
|
14
14
|
from trueseeing.core.ios.device import IOSDevice
|
|
@@ -80,7 +80,7 @@ class EngageCommand(CommandMixin):
|
|
|
80
80
|
|
|
81
81
|
if force:
|
|
82
82
|
ui.warn(f"killing {name}")
|
|
83
|
-
await dev.invoke_frida_passthru(f"frida-kill
|
|
83
|
+
await dev.invoke_frida_passthru(f"frida-kill @dev@ {name}")
|
|
84
84
|
|
|
85
85
|
ui.info(f"starting frida on {name}")
|
|
86
86
|
|
|
@@ -130,7 +130,7 @@ class EngageCommand(CommandMixin):
|
|
|
130
130
|
|
|
131
131
|
if force:
|
|
132
132
|
ui.warn(f"killing {name}")
|
|
133
|
-
await dev.invoke_frida_passthru(f"frida-kill
|
|
133
|
+
await dev.invoke_frida_passthru(f"frida-kill @dev@ {name}")
|
|
134
134
|
|
|
135
135
|
ui.info(f"starting frida on {name}")
|
|
136
136
|
|
|
@@ -173,20 +173,25 @@ class EngageCommand(CommandMixin):
|
|
|
173
173
|
|
|
174
174
|
with TemporaryDirectory() as td:
|
|
175
175
|
from os import chdir, getcwd
|
|
176
|
-
from trueseeing.core.env import get_frida_ios_dump_interp, get_frida_ios_dump_path
|
|
176
|
+
from trueseeing.core.env import get_frida_ios_dump_interp, get_frida_ios_dump_path, get_ios_frida_server_host, get_frida_ios_dump_ssh_host
|
|
177
177
|
from shlex import quote
|
|
178
178
|
cd = getcwd()
|
|
179
|
+
hoststr = get_frida_ios_dump_ssh_host()
|
|
180
|
+
ssh_host, ssh_port = self._parse_host(hoststr, 2222)
|
|
179
181
|
try:
|
|
180
182
|
chdir(td)
|
|
181
183
|
from subprocess import CalledProcessError
|
|
182
184
|
try:
|
|
183
|
-
await dev.invoke_frida_passthru("{interp} {dump} -o t.ipa {name}".format(
|
|
185
|
+
await dev.invoke_frida_passthru("env FRIDA_HOST={host} {interp} {dump} -H {ssh_host} -p {ssh_port} -o t.ipa {name}".format(
|
|
186
|
+
host=get_ios_frida_server_host(),
|
|
184
187
|
interp=get_frida_ios_dump_interp(),
|
|
185
188
|
dump=get_frida_ios_dump_path(),
|
|
189
|
+
ssh_host=ssh_host,
|
|
190
|
+
ssh_port=ssh_port,
|
|
186
191
|
name=quote(pkg),
|
|
187
192
|
))
|
|
188
193
|
except CalledProcessError:
|
|
189
|
-
ui.fatal('
|
|
194
|
+
ui.fatal(f'grab failed (try tunnelling {ssh_host}:{ssh_port} to device port 22 or 44)')
|
|
190
195
|
|
|
191
196
|
from shutil import copy2
|
|
192
197
|
copy2('t.ipa', outfn)
|
|
@@ -195,6 +200,13 @@ class EngageCommand(CommandMixin):
|
|
|
195
200
|
finally:
|
|
196
201
|
chdir(cd)
|
|
197
202
|
|
|
203
|
+
def _parse_host(self, hoststr: str, default_port: int) -> Tuple[str, int]:
|
|
204
|
+
c = hoststr.split(':', maxsplit=1)
|
|
205
|
+
if len(c) > 1:
|
|
206
|
+
return c[0], int(c[1])
|
|
207
|
+
else:
|
|
208
|
+
return c[0], default_port
|
|
209
|
+
|
|
198
210
|
def _get_context(self) -> IPAContext:
|
|
199
211
|
return self._helper.get_context().require_type('ipa') # type:ignore[return-value]
|
|
200
212
|
|
|
@@ -217,7 +229,7 @@ class FridaAttacher:
|
|
|
217
229
|
from asyncio import TimeoutError
|
|
218
230
|
ui.info('attaching to the foreground process')
|
|
219
231
|
try:
|
|
220
|
-
await self._dev.invoke_frida_passthru("frida -
|
|
232
|
+
await self._dev.invoke_frida_passthru("frida @dev@ -F {args}".format(
|
|
221
233
|
args=self._format_args(),
|
|
222
234
|
))
|
|
223
235
|
except (TimeoutError, CalledProcessError):
|
|
@@ -236,7 +248,7 @@ class FridaAttacher:
|
|
|
236
248
|
from subprocess import CalledProcessError
|
|
237
249
|
from asyncio import TimeoutError
|
|
238
250
|
try:
|
|
239
|
-
await self._dev.invoke_frida_passthru("frida -
|
|
251
|
+
await self._dev.invoke_frida_passthru("frida @dev@ -f {name} {args}".format(
|
|
240
252
|
name=name,
|
|
241
253
|
args=self._format_args(),
|
|
242
254
|
), timeout=3.)
|
|
@@ -248,7 +260,7 @@ class FridaAttacher:
|
|
|
248
260
|
from asyncio import TimeoutError
|
|
249
261
|
ui.info('waiting for the process; launch the app on the device in 60s')
|
|
250
262
|
try:
|
|
251
|
-
await self._dev.invoke_frida_passthru("frida -
|
|
263
|
+
await self._dev.invoke_frida_passthru("frida @dev@ -W {name} {args}".format(
|
|
252
264
|
name=name,
|
|
253
265
|
args=self._format_args(),
|
|
254
266
|
), timeout=60.)
|
|
@@ -282,7 +294,7 @@ class FridaTracer:
|
|
|
282
294
|
from asyncio import TimeoutError
|
|
283
295
|
ui.info('attaching to the foreground process')
|
|
284
296
|
try:
|
|
285
|
-
await self._dev.invoke_frida_passthru("frida-trace -
|
|
297
|
+
await self._dev.invoke_frida_passthru("frida-trace @dev@ -F {args}".format(
|
|
286
298
|
args=self._format_args(),
|
|
287
299
|
))
|
|
288
300
|
except (TimeoutError, CalledProcessError):
|
|
@@ -301,7 +313,7 @@ class FridaTracer:
|
|
|
301
313
|
from subprocess import CalledProcessError
|
|
302
314
|
from asyncio import TimeoutError
|
|
303
315
|
try:
|
|
304
|
-
await self._dev.invoke_frida_passthru("frida-trace -
|
|
316
|
+
await self._dev.invoke_frida_passthru("frida-trace @dev@ -f {name} {args}".format(
|
|
305
317
|
name=name,
|
|
306
318
|
args=self._format_args(),
|
|
307
319
|
))
|
|
@@ -313,7 +325,7 @@ class FridaTracer:
|
|
|
313
325
|
from asyncio import TimeoutError
|
|
314
326
|
ui.info('waiting for the process; launch the app on the device in 60s')
|
|
315
327
|
try:
|
|
316
|
-
await self._dev.invoke_frida_passthru("frida-trace -
|
|
328
|
+
await self._dev.invoke_frida_passthru("frida-trace @dev@ -W {name} {args}".format(
|
|
317
329
|
name=name,
|
|
318
330
|
args=self._format_args(),
|
|
319
331
|
))
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from collections import deque
|
|
5
|
+
|
|
6
|
+
from trueseeing.core.model.cmd import CommandMixin
|
|
7
|
+
from trueseeing.core.ui import ui
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from typing import Literal
|
|
11
|
+
from trueseeing.api import CommandHelper, Command, CommandMap
|
|
12
|
+
|
|
13
|
+
UIPatternType = Literal['re', 'xpath']
|
|
14
|
+
|
|
15
|
+
class ReconCommand(CommandMixin):
|
|
16
|
+
def __init__(self, helper: CommandHelper) -> None:
|
|
17
|
+
self._helper = helper
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def create(helper: CommandHelper) -> Command:
|
|
21
|
+
return ReconCommand(helper)
|
|
22
|
+
|
|
23
|
+
def get_commands(self) -> CommandMap:
|
|
24
|
+
return {
|
|
25
|
+
'rp':dict(e=self._recon_list_packages, n='rp', d='recon: list installed packages', t={'ipa'}),
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async def _recon_list_packages(self, args: deque[str]) -> None:
|
|
29
|
+
_ = args.popleft()
|
|
30
|
+
|
|
31
|
+
ui.info('listing packages')
|
|
32
|
+
|
|
33
|
+
import time
|
|
34
|
+
import re
|
|
35
|
+
import io
|
|
36
|
+
from trueseeing.core.ios.device import IOSDevice
|
|
37
|
+
|
|
38
|
+
dev = IOSDevice()
|
|
39
|
+
|
|
40
|
+
at = time.time()
|
|
41
|
+
nr = 0
|
|
42
|
+
for l in io.StringIO(await dev.invoke_frida('frida-ps @dev@ -ai')):
|
|
43
|
+
if l.startswith('----'):
|
|
44
|
+
continue
|
|
45
|
+
m = re.match(r'^\s*([0-9-]+)\s+(.*?)\s+([a-z0-9._-]+)\s*$', l)
|
|
46
|
+
if not m:
|
|
47
|
+
continue
|
|
48
|
+
if m.group(1) == '-':
|
|
49
|
+
ui.info('{bid} ({name})'.format(bid=m.group(3), name=m.group(2)))
|
|
50
|
+
else:
|
|
51
|
+
ui.info('{bid} ({name}) [{pid}]'.format(bid=m.group(3), name=m.group(2), pid=m.group(1)))
|
|
52
|
+
nr += 1
|
|
53
|
+
ui.success('done, {nr} packages found ({t:.02f} sec.)'.format(nr=nr, t=(time.time() - at)))
|
|
@@ -71,7 +71,7 @@ class InspectMode:
|
|
|
71
71
|
sys.ps1, sys.ps2 = ps1, ps2
|
|
72
72
|
|
|
73
73
|
class LambdaConsole(InteractiveConsole):
|
|
74
|
-
def __init__(self, /, runner: Runner, locals: Optional[
|
|
74
|
+
def __init__(self, /, runner: Runner, locals: Optional[Dict[str, Any]] = None) -> None:
|
|
75
75
|
super().__init__(locals=locals, filename='<input>')
|
|
76
76
|
from prompt_toolkit import PromptSession
|
|
77
77
|
self._sess: Any = PromptSession()
|
|
@@ -10,7 +10,7 @@ from trueseeing.core.env import get_home_dir
|
|
|
10
10
|
from trueseeing.core.ui import ui
|
|
11
11
|
|
|
12
12
|
if TYPE_CHECKING:
|
|
13
|
-
from typing import Tuple, Optional
|
|
13
|
+
from typing import Tuple, Optional, AsyncIterator
|
|
14
14
|
from trueseeing.core.context import Context
|
|
15
15
|
from trueseeing.core.db import FileEntry
|
|
16
16
|
|
|
@@ -119,6 +119,32 @@ class APKDisassembler:
|
|
|
119
119
|
|
|
120
120
|
pub.sendMessage('progress.core.asm.disasm.done')
|
|
121
121
|
|
|
122
|
+
@classmethod
|
|
123
|
+
async def get_slices(cls, xapk: str, wd: str) -> AsyncIterator[str]:
|
|
124
|
+
from shlex import quote
|
|
125
|
+
from trueseeing.core.tools import invoke_streaming
|
|
126
|
+
from trueseeing.core.android.tools import toolchains
|
|
127
|
+
|
|
128
|
+
td = wd
|
|
129
|
+
|
|
130
|
+
pub.sendMessage('progress.core.asm.disasm.begin')
|
|
131
|
+
with toolchains() as tc:
|
|
132
|
+
async for l in invoke_streaming(
|
|
133
|
+
'(java -jar {apkeditor} d -o {path} -i {xapk} -dex -t raw)'.format(
|
|
134
|
+
xapk=quote(xapk),
|
|
135
|
+
apkeditor=tc['apkeditor'],
|
|
136
|
+
path=quote(td),
|
|
137
|
+
), redir_stderr=True
|
|
138
|
+
):
|
|
139
|
+
pub.sendMessage('progress.core.asm.disasm.update')
|
|
140
|
+
pub.sendMessage('progress.core.asm.disasm.done')
|
|
141
|
+
|
|
142
|
+
with open(f'{td}/root/manifest.json') as f:
|
|
143
|
+
import json
|
|
144
|
+
dom = json.loads(f.read())
|
|
145
|
+
for s in dom['split_apks']:
|
|
146
|
+
yield os.path.join(td, 'root', s['file'])
|
|
147
|
+
|
|
122
148
|
class APKAssembler:
|
|
123
149
|
@classmethod
|
|
124
150
|
async def assemble_from_path(cls, wd: str, path: str) -> Tuple[str, str]:
|
|
@@ -166,6 +192,34 @@ class APKAssembler:
|
|
|
166
192
|
|
|
167
193
|
return os.path.join(wd, 'output.apk'), os.path.join(wd, 'output.apk.idsig')
|
|
168
194
|
|
|
195
|
+
class APKSigner:
|
|
196
|
+
@classmethod
|
|
197
|
+
async def sign(cls, path: str, wd: str) -> Tuple[str, str]:
|
|
198
|
+
if path.endswith('.xapk'):
|
|
199
|
+
return await APKAssembler.merge_slices(path, wd)
|
|
200
|
+
|
|
201
|
+
import os
|
|
202
|
+
from shlex import quote
|
|
203
|
+
from trueseeing.core.tools import invoke_streaming
|
|
204
|
+
from trueseeing.core.android.tools import toolchains
|
|
205
|
+
|
|
206
|
+
pub.sendMessage('progress.core.asm.asm.begin')
|
|
207
|
+
|
|
208
|
+
with toolchains() as tc:
|
|
209
|
+
async for l in invoke_streaming(
|
|
210
|
+
'(rm -f {wd}/output.apk* && cp {path} {wd}/output.apk && java -jar {apksigner} sign --ks {keystore} --ks-pass pass:android {wd}/output.apk)'.format(
|
|
211
|
+
wd=quote(wd), path=quote(path),
|
|
212
|
+
apksigner=tc['apksigner'],
|
|
213
|
+
keystore=await SigningKey().key(),
|
|
214
|
+
), redir_stderr=True
|
|
215
|
+
):
|
|
216
|
+
pub.sendMessage('progress.core.asm.asm.update')
|
|
217
|
+
|
|
218
|
+
pub.sendMessage('progress.core.asm.asm.done')
|
|
219
|
+
|
|
220
|
+
return os.path.join(wd, 'output.apk'), os.path.join(wd, 'output.apk.idsig')
|
|
221
|
+
|
|
222
|
+
|
|
169
223
|
class SigningKey:
|
|
170
224
|
_path: str
|
|
171
225
|
|