libidentifier 0.2.0rc1__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.
Files changed (103) hide show
  1. libidentifier-0.2.0rc1/CHANGELOG.md +42 -0
  2. libidentifier-0.2.0rc1/LICENSE +62 -0
  3. libidentifier-0.2.0rc1/MANIFEST.in +15 -0
  4. libidentifier-0.2.0rc1/PKG-INFO +156 -0
  5. libidentifier-0.2.0rc1/README.md +127 -0
  6. libidentifier-0.2.0rc1/THIRD_PARTY_NOTICES.md +15 -0
  7. libidentifier-0.2.0rc1/benchmarks/corpus.example.json +11 -0
  8. libidentifier-0.2.0rc1/benchmarks/run.py +84 -0
  9. libidentifier-0.2.0rc1/catalog/references.example.json +13 -0
  10. libidentifier-0.2.0rc1/catalog/references.json +63 -0
  11. libidentifier-0.2.0rc1/docs/architecture.md +51 -0
  12. libidentifier-0.2.0rc1/docs/development/README.md +28 -0
  13. libidentifier-0.2.0rc1/docs/development/archive/technical-specification-v1.md +595 -0
  14. libidentifier-0.2.0rc1/docs/development/decisions/0001-stage-2.md +34 -0
  15. libidentifier-0.2.0rc1/docs/development/release-readiness.md +51 -0
  16. libidentifier-0.2.0rc1/docs/development/roadmap.md +24 -0
  17. libidentifier-0.2.0rc1/docs/development/stages/future.md +9 -0
  18. libidentifier-0.2.0rc1/docs/development/stages/stage-1.md +12 -0
  19. libidentifier-0.2.0rc1/docs/development/stages/stage-2.md +60 -0
  20. libidentifier-0.2.0rc1/docs/development/stages/stage-3.md +18 -0
  21. libidentifier-0.2.0rc1/docs/development/testing.md +85 -0
  22. libidentifier-0.2.0rc1/docs/development/validation/cleanup-windows-2026-10-20.md +61 -0
  23. libidentifier-0.2.0rc1/docs/development/validation/managed-cli-windows-2026-10-21.md +82 -0
  24. libidentifier-0.2.0rc1/docs/development/validation/phase-a-windows-2026-10-20.md +69 -0
  25. libidentifier-0.2.0rc1/docs/development/validation/stage2-matrix.json +201 -0
  26. libidentifier-0.2.0rc1/docs/development/validation/stage2-pilot.json +166 -0
  27. libidentifier-0.2.0rc1/docs/development/validation/stage2-validation.md +202 -0
  28. libidentifier-0.2.0rc1/docs/fingerprints.md +18 -0
  29. libidentifier-0.2.0rc1/docs/formats.md +19 -0
  30. libidentifier-0.2.0rc1/docs/installation.md +179 -0
  31. libidentifier-0.2.0rc1/docs/integration.md +593 -0
  32. libidentifier-0.2.0rc1/docs/limitations.md +31 -0
  33. libidentifier-0.2.0rc1/docs/profile-database.md +68 -0
  34. libidentifier-0.2.0rc1/docs/quickstart.md +246 -0
  35. libidentifier-0.2.0rc1/docs/releases.md +213 -0
  36. libidentifier-0.2.0rc1/pyproject.toml +45 -0
  37. libidentifier-0.2.0rc1/setup.cfg +4 -0
  38. libidentifier-0.2.0rc1/src/libidentifier/__init__.py +36 -0
  39. libidentifier-0.2.0rc1/src/libidentifier/api.py +90 -0
  40. libidentifier-0.2.0rc1/src/libidentifier/archive.py +133 -0
  41. libidentifier-0.2.0rc1/src/libidentifier/cli.py +340 -0
  42. libidentifier-0.2.0rc1/src/libidentifier/cli_resources.py +36 -0
  43. libidentifier-0.2.0rc1/src/libidentifier/cli_setup.py +177 -0
  44. libidentifier-0.2.0rc1/src/libidentifier/config.py +54 -0
  45. libidentifier-0.2.0rc1/src/libidentifier/detect.py +30 -0
  46. libidentifier-0.2.0rc1/src/libidentifier/errors.py +30 -0
  47. libidentifier-0.2.0rc1/src/libidentifier/extractors/__init__.py +2 -0
  48. libidentifier-0.2.0rc1/src/libidentifier/extractors/dex.py +121 -0
  49. libidentifier-0.2.0rc1/src/libidentifier/extractors/dex_tables.py +137 -0
  50. libidentifier-0.2.0rc1/src/libidentifier/extractors/elf.py +66 -0
  51. libidentifier-0.2.0rc1/src/libidentifier/extractors/instructions.py +77 -0
  52. libidentifier-0.2.0rc1/src/libidentifier/extractors/metadata.py +99 -0
  53. libidentifier-0.2.0rc1/src/libidentifier/extractors/version_metadata.py +72 -0
  54. libidentifier-0.2.0rc1/src/libidentifier/fingerprint/__init__.py +2 -0
  55. libidentifier-0.2.0rc1/src/libidentifier/fingerprint/dex_v2.py +97 -0
  56. libidentifier-0.2.0rc1/src/libidentifier/fingerprint/elf_v1.py +16 -0
  57. libidentifier-0.2.0rc1/src/libidentifier/grouping.py +74 -0
  58. libidentifier-0.2.0rc1/src/libidentifier/inventory.py +260 -0
  59. libidentifier-0.2.0rc1/src/libidentifier/matcher.py +381 -0
  60. libidentifier-0.2.0rc1/src/libidentifier/models.py +423 -0
  61. libidentifier-0.2.0rc1/src/libidentifier/profiles/__init__.py +2 -0
  62. libidentifier-0.2.0rc1/src/libidentifier/profiles/builder.py +182 -0
  63. libidentifier-0.2.0rc1/src/libidentifier/profiles/catalog.py +135 -0
  64. libidentifier-0.2.0rc1/src/libidentifier/profiles/distribution.py +303 -0
  65. libidentifier-0.2.0rc1/src/libidentifier/profiles/fetcher.py +141 -0
  66. libidentifier-0.2.0rc1/src/libidentifier/profiles/pom.py +66 -0
  67. libidentifier-0.2.0rc1/src/libidentifier/profiles/schema.py +137 -0
  68. libidentifier-0.2.0rc1/src/libidentifier/profiles/store.py +212 -0
  69. libidentifier-0.2.0rc1/src/libidentifier/purl.py +36 -0
  70. libidentifier-0.2.0rc1/src/libidentifier/relationships.py +168 -0
  71. libidentifier-0.2.0rc1/src/libidentifier/sbom.py +62 -0
  72. libidentifier-0.2.0rc1/src/libidentifier/serialization.py +53 -0
  73. libidentifier-0.2.0rc1/src/libidentifier/table.py +254 -0
  74. libidentifier-0.2.0rc1/src/libidentifier/version.py +2 -0
  75. libidentifier-0.2.0rc1/src/libidentifier/vulnerabilities/__init__.py +2 -0
  76. libidentifier-0.2.0rc1/src/libidentifier/vulnerabilities/correlate.py +164 -0
  77. libidentifier-0.2.0rc1/src/libidentifier/vulnerabilities/database.py +213 -0
  78. libidentifier-0.2.0rc1/src/libidentifier/vulnerabilities/models.py +155 -0
  79. libidentifier-0.2.0rc1/src/libidentifier/vulnerabilities/runner.py +148 -0
  80. libidentifier-0.2.0rc1/src/libidentifier/vulnerabilities/setup.py +74 -0
  81. libidentifier-0.2.0rc1/src/libidentifier.egg-info/PKG-INFO +156 -0
  82. libidentifier-0.2.0rc1/src/libidentifier.egg-info/SOURCES.txt +101 -0
  83. libidentifier-0.2.0rc1/src/libidentifier.egg-info/dependency_links.txt +1 -0
  84. libidentifier-0.2.0rc1/src/libidentifier.egg-info/entry_points.txt +2 -0
  85. libidentifier-0.2.0rc1/src/libidentifier.egg-info/requires.txt +9 -0
  86. libidentifier-0.2.0rc1/src/libidentifier.egg-info/top_level.txt +1 -0
  87. libidentifier-0.2.0rc1/tests/conftest.py +299 -0
  88. libidentifier-0.2.0rc1/tests/fixtures/scan-v1-legacy.json +15 -0
  89. libidentifier-0.2.0rc1/tests/test_catalog_fetch_rebuild.py +65 -0
  90. libidentifier-0.2.0rc1/tests/test_cli_and_sbom.py +72 -0
  91. libidentifier-0.2.0rc1/tests/test_cli_setup.py +215 -0
  92. libidentifier-0.2.0rc1/tests/test_detect_and_archive.py +37 -0
  93. libidentifier-0.2.0rc1/tests/test_dex_elf_features.py +60 -0
  94. libidentifier-0.2.0rc1/tests/test_frameworks_and_contract.py +247 -0
  95. libidentifier-0.2.0rc1/tests/test_offline_assessment.py +278 -0
  96. libidentifier-0.2.0rc1/tests/test_osv_convenience.py +185 -0
  97. libidentifier-0.2.0rc1/tests/test_profile_distribution.py +203 -0
  98. libidentifier-0.2.0rc1/tests/test_profile_matching.py +123 -0
  99. libidentifier-0.2.0rc1/tests/test_sca_readiness.py +262 -0
  100. libidentifier-0.2.0rc1/tests/test_scanner_compatibility.py +122 -0
  101. libidentifier-0.2.0rc1/tests/test_stage2.py +303 -0
  102. libidentifier-0.2.0rc1/tests/test_table_and_score.py +147 -0
  103. libidentifier-0.2.0rc1/tools/check_distributions.py +42 -0
@@ -0,0 +1,42 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0rc1 — Stage 2 preview (publication pending)
4
+
5
+ - Complete PyPI/GitHub source installation routes, Windows activation-free
6
+ commands, result interpretation, managed-path updates and user troubleshooting.
7
+ README/PyPI links lead to installation/usage before the advanced API reference.
8
+
9
+ - Managed `scan app.apk` first-run setup with one consent prompt, `--yes`, strict
10
+ `--offline`, project-pinned scanner downloads and persistent per-user resources.
11
+ - `--vulns` alias, table default for managed scans, preserved explicit-profile
12
+ JSON defaults and download-free analysis APIs; optional failures retain inventory.
13
+
14
+ - Explicit profile packaging/acquisition APIs and CLI, portable release manifests,
15
+ hashes, engine compatibility, bounded downloads/decompression, SQLite integrity
16
+ checks and atomic install with explicit replacement. Analysis remains offline.
17
+ - Single-source package version, PyPI metadata, wheel/sdist content checks,
18
+ Trusted Publishing workflow and maintainer publication instructions.
19
+
20
+ - Release-first roadmap: preview package and small schema-2 profile distribution
21
+ before catalog expansion and Stage 3 accuracy qualification.
22
+ - Removed obsolete generated validation output and schema-1 sample databases;
23
+ retained selected dated evidence under `docs/development/validation/`.
24
+ - Canonical DEX implementation now uses `fingerprint/dex_v2.py`; optional local
25
+ qualification resources use ignored `.local/` and `.tools/` directories.
26
+
27
+ - Canonical DEX descriptors/interfaces and location-aware ownership uncertainty.
28
+ - Additive evidence, analysis status, unattributed clusters and typed structural,
29
+ ordinary invocation, published-dependency and component relationship models.
30
+ - Internal reference schema 2 separates releases, artifacts, variants, fingerprints
31
+ and occurrences; canonical fingerprints require an explicit profile rebuild.
32
+ - Direct POM/local-property interpretation and attributable embedded Maven metadata.
33
+ - Contributor documentation, preserved historical specification, contract fixtures,
34
+ platform CI and a benchmark harness. Existing OSV provisioning/discovery/offline
35
+ execution and compact table behavior are preserved.
36
+ - CI validates regular package installations and retains per-environment runtime,
37
+ scanner and JUnit evidence, including skip reasons.
38
+
39
+ ## 0.1.0
40
+
41
+ - Initial Stage 1 implementation with APK/DEX/ELF inspection, DEX shape fingerprints, ELF identity fingerprints, SQLite profile building, offline matching, JSON output, CLI commands, and CycloneDX export for exact high-confidence versions.
42
+
@@ -0,0 +1,62 @@
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ https://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
10
+
11
+ "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
12
+
13
+ "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
14
+
15
+ "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
16
+
17
+ "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
18
+
19
+ "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
20
+
21
+ "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License.
22
+
23
+ "Derivative Works" shall mean any work, whether in Source or Object form, that is based on or derived from the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. Derivative Works shall not include works that remain separable from, or merely link or bind by name to the interfaces of, the Work.
24
+
25
+ "Contribution" shall mean any work of authorship that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner.
26
+
27
+ "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
28
+
29
+ 2. Grant of Copyright License.
30
+
31
+ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
32
+
33
+ 3. Grant of Patent License.
34
+
35
+ Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work. If You institute patent litigation against any entity alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
36
+
37
+ 4. Redistribution.
38
+
39
+ You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet these conditions: You must give recipients a copy of this License; modified files must carry prominent notices stating that You changed the files; and You must retain copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding notices that do not pertain to any part of the Derivative Works. If the Work includes a NOTICE file, Derivative Works that You distribute must include a readable copy of applicable attribution notices.
40
+
41
+ 5. Submission of Contributions.
42
+
43
+ Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License.
44
+
45
+ 6. Trademarks.
46
+
47
+ This License does not grant permission to use trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work.
48
+
49
+ 7. Disclaimer of Warranty.
50
+
51
+ Unless required by applicable law or agreed to in writing, Licensor provides the Work on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
52
+
53
+ 8. Limitation of Liability.
54
+
55
+ In no event and under no legal theory, whether in tort, contract, or otherwise, unless required by applicable law or agreed to in writing, shall any Contributor be liable to You for damages arising as a result of this License or out of the use or inability to use the Work.
56
+
57
+ 9. Accepting Warranty or Additional Liability.
58
+
59
+ While redistributing the Work or Derivative Works thereof, You may choose to offer support, warranty, indemnity, or other liability obligations. In accepting such obligations, You act only on Your own behalf and on Your sole responsibility.
60
+
61
+ END OF TERMS AND CONDITIONS
62
+
@@ -0,0 +1,15 @@
1
+ include LICENSE THIRD_PARTY_NOTICES.md CHANGELOG.md
2
+ recursive-include docs *.md *.json
3
+ recursive-exclude docs __pycache__ *integration-moraine* *moraine-integration*
4
+ recursive-include catalog *.json
5
+ recursive-include benchmarks *.py *.json
6
+ recursive-include tests *.py *.json
7
+ recursive-include tools *.py
8
+ prune .local
9
+ prune .tools
10
+ prune .development-deps
11
+ prune .release-venv
12
+ prune samples
13
+ prune test-results
14
+ prune build
15
+ exclude moraine-integration.md
@@ -0,0 +1,156 @@
1
+ Metadata-Version: 2.4
2
+ Name: libidentifier
3
+ Version: 0.2.0rc1
4
+ Summary: Offline identification of compiled Android and native libraries from local fingerprints
5
+ Author: LibIdentifier authors
6
+ License-Expression: Apache-2.0
7
+ Project-URL: Repository, https://github.com/ernestomgz/libidentifier
8
+ Project-URL: Documentation, https://github.com/ernestomgz/libidentifier/blob/main/docs/quickstart.md
9
+ Project-URL: Installation, https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md
10
+ Project-URL: API reference, https://github.com/ernestomgz/libidentifier/blob/main/docs/integration.md
11
+ Project-URL: Issues, https://github.com/ernestomgz/libidentifier/issues
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.11
15
+ Classifier: Programming Language :: Python :: 3.12
16
+ Classifier: Programming Language :: Python :: 3.13
17
+ Requires-Python: >=3.11
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ License-File: THIRD_PARTY_NOTICES.md
21
+ Requires-Dist: lief==0.17.1
22
+ Requires-Dist: packaging>=24
23
+ Provides-Extra: dev
24
+ Requires-Dist: pytest>=8; extra == "dev"
25
+ Provides-Extra: release
26
+ Requires-Dist: build>=1.2; extra == "release"
27
+ Requires-Dist: twine>=6; extra == "release"
28
+ Dynamic: license-file
29
+
30
+ # LibIdentifier
31
+
32
+ Identify known libraries and frameworks in Android APKs, DEX and native ELF files.
33
+ LibIdentifier is an independent Python package and CLI. Analysis runs locally;
34
+ your APK is never uploaded. Optional OSV assessment uses a local advisory database
35
+ and does not establish reachability or exploitability.
36
+
37
+ **Preview:** the initial official profile catalog covers six library families and
38
+ eight releases. No match does not mean no third-party code. See
39
+ [limitations](https://github.com/ernestomgz/libidentifier/blob/main/docs/limitations.md). The PyPI route requires a published package, and managed
40
+ library scans require published profiles. Check [installation availability](https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md#before-you-start)
41
+ or use the source route and profile-free inspection below.
42
+
43
+ ## Install from PyPI or GitHub
44
+
45
+ Python 3.12 is recommended. New to Python environments? Follow the complete
46
+ [Windows/Linux installation guide](https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md), including the
47
+ activation-free Windows option.
48
+
49
+ **Released package from PyPI** (after publication), in your Python environment:
50
+
51
+ ```powershell
52
+ python -m pip install "libidentifier==0.2.0rc1"
53
+ ```
54
+
55
+ **Reviewed source from GitHub**, in your Python environment:
56
+
57
+ ```powershell
58
+ git clone https://github.com/ernestomgz/libidentifier.git
59
+ cd libidentifier
60
+ python -m pip install .
61
+ ```
62
+
63
+ Both methods provide the same command. Check the installation, then scan your
64
+ own APK (replace the example path):
65
+
66
+ ```powershell
67
+ libidentifier --version
68
+ libidentifier scan "app.apk" --vulns
69
+ ```
70
+
71
+ The source route installs the code before PyPI publication, but automatic library
72
+ scans still require the official profiles to be available. Until then,
73
+ `libidentifier inspect "app.apk" --format table` works without profiles; see
74
+ [installation verification](https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md#verify-without-profiles).
75
+
76
+ `--vulnerabilities` is the long spelling of `--vulns`. For library identification
77
+ without advisory assessment:
78
+
79
+ ```powershell
80
+ libidentifier scan app.apk
81
+ ```
82
+
83
+ On first use, the CLI lists missing resources, shows their destination and asks
84
+ `Download and set up these resources? [y/N]`. Accept to install the official
85
+ profiles and, when requested, the project-qualified OSV-Scanner and Maven advisory
86
+ data. Later scans reuse them. Existing resources are never silently updated.
87
+ Without vulnerability assessment, only profiles are needed.
88
+
89
+ Managed scans print the compact table. Setup messages go to stderr. Windows
90
+ resources live under `%LOCALAPPDATA%/LibIdentifier`; Linux uses
91
+ `${XDG_CACHE_HOME:-~/.cache}/libidentifier`. `LIBIDENTIFIER_HOME` overrides the
92
+ managed root. Automatic scanner installation currently supports Windows/Linux
93
+ x64 and uses project-pinned URLs and SHA-256 values, never GitHub's latest tag.
94
+
95
+ ## Useful options
96
+
97
+ ```powershell
98
+ # Authorize missing-resource setup in scripts; never prompts.
99
+ libidentifier scan app.apk --vulns --yes
100
+
101
+ # Reuse installed resources without any downloads.
102
+ libidentifier scan app.apk --vulns --offline
103
+
104
+ # JSON instead of a table; --output alone also selects JSON in managed mode.
105
+ libidentifier scan app.apk --vulns --output results.json
106
+
107
+ # Existing explicit usage retains its JSON default and resource overrides.
108
+ libidentifier scan app.apk --profiles custom.sqlite --format json --output results.json
109
+ libidentifier identify app.apk --profiles custom.sqlite --format table
110
+ ```
111
+
112
+ A noninteractive first run needs `--yes` or preinstalled resources. `--offline`
113
+ overrides `--yes`. If optional vulnerability setup fails, identification is
114
+ preserved with an explicit unassessed result. Required profile failures stop the
115
+ scan. Continue with [first scan, result meanings, advanced options and resource updates](https://github.com/ernestomgz/libidentifier/blob/main/docs/quickstart.md).
116
+
117
+ ## Python API
118
+
119
+ Use a local database you explicitly provisioned; the managed CLI cache is not
120
+ automatically copied to your working directory. See the
121
+ [complete API setup example](https://github.com/ernestomgz/libidentifier/blob/main/docs/quickstart.md#use-the-python-api).
122
+
123
+ ```python
124
+ from pathlib import Path
125
+ from libidentifier import identify
126
+
127
+ result = identify(Path("app.apk"), profiles=Path("profiles.sqlite"))
128
+ result.write_json(Path("libraries.json"))
129
+ ```
130
+
131
+ Analysis APIs never prompt, install tools or download data. Explicit maintenance
132
+ APIs are available for consumers that manage their own setup. The authoritative
133
+ [API/JSON guide](https://github.com/ernestomgz/libidentifier/blob/main/docs/integration.md) documents models, coverage, errors, SBOM,
134
+ profile provisioning and offline advisory assessment. Structural matching normally
135
+ identifies families; exact installed versions require stronger evidence.
136
+
137
+ ## Documentation and development
138
+
139
+ | I want to… | Read |
140
+ |---|---|
141
+ | Install from pip, GitHub or a source ZIP | [Installation](https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md) |
142
+ | Scan, save output, use offline mode or repair setup | [Usage guide](https://github.com/ernestomgz/libidentifier/blob/main/docs/quickstart.md) |
143
+ | Integrate the Python API or consume JSON | [Public contract](https://github.com/ernestomgz/libidentifier/blob/main/docs/integration.md) |
144
+ | Build my own reference catalog | [Profile database](https://github.com/ernestomgz/libidentifier/blob/main/docs/profile-database.md) |
145
+ | Publish/update official releases | [Maintainer release guide](https://github.com/ernestomgz/libidentifier/blob/main/docs/releases.md) |
146
+
147
+ Python 3.11+; `lief==0.17.1`. To use a reviewed checkout before publication:
148
+
149
+ ```powershell
150
+ python -m pip install -e ".[dev]"
151
+ ```
152
+
153
+ Tests generate synthetic DEX/APK/ELF fixtures. JAR/AAR **profile generation** needs
154
+ local D8; ordinary scans do not need Java or the Android SDK. See the
155
+ [developer index](https://github.com/ernestomgz/libidentifier/blob/main/docs/development/README.md), [release checklist](https://github.com/ernestomgz/libidentifier/blob/main/docs/development/release-readiness.md),
156
+ [Stage 2 acceptance](https://github.com/ernestomgz/libidentifier/blob/main/docs/development/stages/stage-2.md) and [contributor instructions](https://github.com/ernestomgz/libidentifier/blob/main/AGENTS.md).
@@ -0,0 +1,127 @@
1
+ # LibIdentifier
2
+
3
+ Identify known libraries and frameworks in Android APKs, DEX and native ELF files.
4
+ LibIdentifier is an independent Python package and CLI. Analysis runs locally;
5
+ your APK is never uploaded. Optional OSV assessment uses a local advisory database
6
+ and does not establish reachability or exploitability.
7
+
8
+ **Preview:** the initial official profile catalog covers six library families and
9
+ eight releases. No match does not mean no third-party code. See
10
+ [limitations](https://github.com/ernestomgz/libidentifier/blob/main/docs/limitations.md). The PyPI route requires a published package, and managed
11
+ library scans require published profiles. Check [installation availability](https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md#before-you-start)
12
+ or use the source route and profile-free inspection below.
13
+
14
+ ## Install from PyPI or GitHub
15
+
16
+ Python 3.12 is recommended. New to Python environments? Follow the complete
17
+ [Windows/Linux installation guide](https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md), including the
18
+ activation-free Windows option.
19
+
20
+ **Released package from PyPI** (after publication), in your Python environment:
21
+
22
+ ```powershell
23
+ python -m pip install "libidentifier==0.2.0rc1"
24
+ ```
25
+
26
+ **Reviewed source from GitHub**, in your Python environment:
27
+
28
+ ```powershell
29
+ git clone https://github.com/ernestomgz/libidentifier.git
30
+ cd libidentifier
31
+ python -m pip install .
32
+ ```
33
+
34
+ Both methods provide the same command. Check the installation, then scan your
35
+ own APK (replace the example path):
36
+
37
+ ```powershell
38
+ libidentifier --version
39
+ libidentifier scan "app.apk" --vulns
40
+ ```
41
+
42
+ The source route installs the code before PyPI publication, but automatic library
43
+ scans still require the official profiles to be available. Until then,
44
+ `libidentifier inspect "app.apk" --format table` works without profiles; see
45
+ [installation verification](https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md#verify-without-profiles).
46
+
47
+ `--vulnerabilities` is the long spelling of `--vulns`. For library identification
48
+ without advisory assessment:
49
+
50
+ ```powershell
51
+ libidentifier scan app.apk
52
+ ```
53
+
54
+ On first use, the CLI lists missing resources, shows their destination and asks
55
+ `Download and set up these resources? [y/N]`. Accept to install the official
56
+ profiles and, when requested, the project-qualified OSV-Scanner and Maven advisory
57
+ data. Later scans reuse them. Existing resources are never silently updated.
58
+ Without vulnerability assessment, only profiles are needed.
59
+
60
+ Managed scans print the compact table. Setup messages go to stderr. Windows
61
+ resources live under `%LOCALAPPDATA%/LibIdentifier`; Linux uses
62
+ `${XDG_CACHE_HOME:-~/.cache}/libidentifier`. `LIBIDENTIFIER_HOME` overrides the
63
+ managed root. Automatic scanner installation currently supports Windows/Linux
64
+ x64 and uses project-pinned URLs and SHA-256 values, never GitHub's latest tag.
65
+
66
+ ## Useful options
67
+
68
+ ```powershell
69
+ # Authorize missing-resource setup in scripts; never prompts.
70
+ libidentifier scan app.apk --vulns --yes
71
+
72
+ # Reuse installed resources without any downloads.
73
+ libidentifier scan app.apk --vulns --offline
74
+
75
+ # JSON instead of a table; --output alone also selects JSON in managed mode.
76
+ libidentifier scan app.apk --vulns --output results.json
77
+
78
+ # Existing explicit usage retains its JSON default and resource overrides.
79
+ libidentifier scan app.apk --profiles custom.sqlite --format json --output results.json
80
+ libidentifier identify app.apk --profiles custom.sqlite --format table
81
+ ```
82
+
83
+ A noninteractive first run needs `--yes` or preinstalled resources. `--offline`
84
+ overrides `--yes`. If optional vulnerability setup fails, identification is
85
+ preserved with an explicit unassessed result. Required profile failures stop the
86
+ scan. Continue with [first scan, result meanings, advanced options and resource updates](https://github.com/ernestomgz/libidentifier/blob/main/docs/quickstart.md).
87
+
88
+ ## Python API
89
+
90
+ Use a local database you explicitly provisioned; the managed CLI cache is not
91
+ automatically copied to your working directory. See the
92
+ [complete API setup example](https://github.com/ernestomgz/libidentifier/blob/main/docs/quickstart.md#use-the-python-api).
93
+
94
+ ```python
95
+ from pathlib import Path
96
+ from libidentifier import identify
97
+
98
+ result = identify(Path("app.apk"), profiles=Path("profiles.sqlite"))
99
+ result.write_json(Path("libraries.json"))
100
+ ```
101
+
102
+ Analysis APIs never prompt, install tools or download data. Explicit maintenance
103
+ APIs are available for consumers that manage their own setup. The authoritative
104
+ [API/JSON guide](https://github.com/ernestomgz/libidentifier/blob/main/docs/integration.md) documents models, coverage, errors, SBOM,
105
+ profile provisioning and offline advisory assessment. Structural matching normally
106
+ identifies families; exact installed versions require stronger evidence.
107
+
108
+ ## Documentation and development
109
+
110
+ | I want to… | Read |
111
+ |---|---|
112
+ | Install from pip, GitHub or a source ZIP | [Installation](https://github.com/ernestomgz/libidentifier/blob/main/docs/installation.md) |
113
+ | Scan, save output, use offline mode or repair setup | [Usage guide](https://github.com/ernestomgz/libidentifier/blob/main/docs/quickstart.md) |
114
+ | Integrate the Python API or consume JSON | [Public contract](https://github.com/ernestomgz/libidentifier/blob/main/docs/integration.md) |
115
+ | Build my own reference catalog | [Profile database](https://github.com/ernestomgz/libidentifier/blob/main/docs/profile-database.md) |
116
+ | Publish/update official releases | [Maintainer release guide](https://github.com/ernestomgz/libidentifier/blob/main/docs/releases.md) |
117
+
118
+ Python 3.11+; `lief==0.17.1`. To use a reviewed checkout before publication:
119
+
120
+ ```powershell
121
+ python -m pip install -e ".[dev]"
122
+ ```
123
+
124
+ Tests generate synthetic DEX/APK/ELF fixtures. JAR/AAR **profile generation** needs
125
+ local D8; ordinary scans do not need Java or the Android SDK. See the
126
+ [developer index](https://github.com/ernestomgz/libidentifier/blob/main/docs/development/README.md), [release checklist](https://github.com/ernestomgz/libidentifier/blob/main/docs/development/release-readiness.md),
127
+ [Stage 2 acceptance](https://github.com/ernestomgz/libidentifier/blob/main/docs/development/stages/stage-2.md) and [contributor instructions](https://github.com/ernestomgz/libidentifier/blob/main/AGENTS.md).
@@ -0,0 +1,15 @@
1
+ # Third-Party Notices
2
+
3
+ LibIdentifier Stage 1 contains original implementation code and does not vendor Androguard, LibScout, OSV-Scanner, Android SDK artifacts, or third-party library binaries.
4
+
5
+ Runtime dependency:
6
+
7
+ - LIEF, used for DEX and ELF parsing. See https://lief.re/ and the LIEF project license for redistribution terms.
8
+
9
+ Research influence:
10
+
11
+ - LibScout's profile-and-match approach informed the high-level fingerprinting strategy.
12
+ - Androguard documentation informed Android bytecode terminology.
13
+
14
+ No upstream source files from those projects were copied into this implementation.
15
+
@@ -0,0 +1,11 @@
1
+ {
2
+ "schema_version": 1,
3
+ "samples": [
4
+ {
5
+ "path": "fixtures/independent.apk",
6
+ "ground_truth_complete": true,
7
+ "components": [{"family_purl": "pkg:maven/example/demo", "version": "1.0"}],
8
+ "build": {"compiler": "record actual version", "transformation": "unoptimized", "keep_rules_sha256": null}
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,84 @@
1
+ """Isolated scan measurements; quality metrics require complete build ground truth.
2
+
3
+ python benchmarks/run.py --profiles profiles.sqlite --corpus corpus.json
4
+ Corpus paths are relative to the manifest. Each sample runs in a new process.
5
+ """
6
+ from __future__ import annotations
7
+ import argparse
8
+ import json
9
+ import os
10
+ from pathlib import Path
11
+ import subprocess
12
+ import sys
13
+ import time
14
+
15
+
16
+ def peak_rss():
17
+ if os.name != 'nt':
18
+ import resource
19
+ return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss * 1024
20
+ import ctypes
21
+ from ctypes import wintypes
22
+ class Counters(ctypes.Structure):
23
+ _fields_ = [('cb',wintypes.DWORD),('PageFaultCount',wintypes.DWORD)] + [(name,ctypes.c_size_t) for name in (
24
+ 'PeakWorkingSetSize','WorkingSetSize','QuotaPeakPagedPoolUsage','QuotaPagedPoolUsage',
25
+ 'QuotaPeakNonPagedPoolUsage','QuotaNonPagedPoolUsage','PagefileUsage','PeakPagefileUsage')]
26
+ counters=Counters();counters.cb=ctypes.sizeof(counters)
27
+ kernel=ctypes.WinDLL('kernel32',use_last_error=True)
28
+ kernel.GetCurrentProcess.restype=wintypes.HANDLE
29
+ psapi=ctypes.WinDLL('psapi',use_last_error=True)
30
+ psapi.GetProcessMemoryInfo.argtypes=[wintypes.HANDLE,ctypes.POINTER(Counters),wintypes.DWORD]
31
+ if not psapi.GetProcessMemoryInfo(kernel.GetCurrentProcess(),ctypes.byref(counters),counters.cb):
32
+ raise ctypes.WinError(ctypes.get_last_error())
33
+ return counters.PeakWorkingSetSize
34
+
35
+
36
+ def worker(path,profiles):
37
+ import lief
38
+ from libidentifier import identify
39
+ started=time.perf_counter();result=identify(path,profiles=profiles)
40
+ return {'input':result.input.to_dict(),'tool_version':result.tool_version,'python':sys.version.split()[0],
41
+ 'lief':lief.__version__,'profile_database':result.profile_database.to_dict(),
42
+ 'seconds':time.perf_counter()-started,'peak_rss_bytes':peak_rss(),
43
+ 'classes':result.coverage.analyzed_count['classes'],'unknown':result.coverage.unknown_classes_total,
44
+ 'clusters':len(result.unattributed_clusters),'relationships':len(result.relationships),
45
+ 'analysis_runs':[r.to_dict() for r in result.analysis_runs],
46
+ 'errors':[e.to_dict() for e in result.errors],
47
+ 'components':[{'family_purl':c.family_purl,'version':c.version} for c in result.components]}
48
+
49
+
50
+ def quality(rows, samples):
51
+ tp=fp=fn=exact=correct=known=0
52
+ for row,sample in zip(rows,samples):
53
+ if not sample.get('ground_truth_complete'):
54
+ continue
55
+ expected={c['family_purl']:c.get('version') for c in sample['components']}
56
+ observed={c['family_purl']:c['version'] for c in row['components']}
57
+ tp+=len(expected.keys()&observed.keys());fp+=len(observed.keys()-expected.keys());fn+=len(expected.keys()-observed.keys())
58
+ known+=sum(v is not None for v in expected.values())
59
+ for family,version in observed.items():
60
+ if version is not None:
61
+ exact+=1;correct+=family in expected and expected[family]==version
62
+ return {'family_true_positive':tp,'family_false_positive':fp,'family_false_negative':fn,
63
+ 'exact_version_predictions':exact,'correct_exact_versions':correct,'ground_truth_versioned_components':known,
64
+ 'family_precision':tp/(tp+fp) if tp+fp else None,'family_recall':tp/(tp+fn) if tp+fn else None,
65
+ 'exact_version_precision':correct/exact if exact else None,'exact_version_coverage':correct/known if known else None}
66
+
67
+
68
+ def main():
69
+ parser=argparse.ArgumentParser();parser.add_argument('--profiles',required=True)
70
+ parser.add_argument('--corpus');parser.add_argument('--worker')
71
+ args=parser.parse_args()
72
+ if args.worker:
73
+ print(json.dumps(worker(args.worker,args.profiles)));return
74
+ corpus_path=Path(args.corpus).resolve();corpus=json.loads(corpus_path.read_text())
75
+ if corpus.get('schema_version')!=1:raise ValueError('Unsupported corpus schema')
76
+ rows=[]
77
+ for sample in corpus['samples']:
78
+ completed=subprocess.run([sys.executable,str(Path(__file__).resolve()),'--profiles',str(Path(args.profiles).resolve()),
79
+ '--worker',str((corpus_path.parent/sample['path']).resolve())],check=True,capture_output=True,text=True,encoding='utf-8',timeout=300)
80
+ rows.append(json.loads(completed.stdout))
81
+ print(json.dumps({'schema_version':1,'platform':sys.platform,'samples':rows,'quality':quality(rows,corpus['samples'])},indent=2))
82
+
83
+
84
+ if __name__=='__main__':main()
@@ -0,0 +1,13 @@
1
+ {
2
+ "schema_version": 1,
3
+ "references": [
4
+ {
5
+ "purl": "pkg:maven/example/library@1.0.0",
6
+ "path": "reference-artifacts/library-1.0.0.dex",
7
+ "sha256": "<verified-reference-hash>",
8
+ "license": "Apache-2.0",
9
+ "provenance_url": "https://example.invalid/reference"
10
+ }
11
+ ]
12
+ }
13
+
@@ -0,0 +1,63 @@
1
+ {
2
+ "schema_version": 1,
3
+ "fingerprint_algorithm": "dex-shape-v2-canonical+elf-identity-v1",
4
+ "references": [
5
+ {
6
+ "purl": "pkg:maven/com.google.code.gson/gson@2.11.0",
7
+ "repository": "maven-central",
8
+ "url": "https://repo.maven.apache.org/maven2/com/google/code/gson/gson/2.11.0/gson-2.11.0.jar",
9
+ "sha256": "57928d6e5a6edeb2abd3770a8f95ba44dce45f3b23b7a9dc2b309c581552a78b",
10
+ "license": "Apache-2.0"
11
+ },
12
+ {
13
+ "purl": "pkg:maven/commons-io/commons-io@2.16.1",
14
+ "repository": "maven-central",
15
+ "url": "https://repo.maven.apache.org/maven2/commons-io/commons-io/2.16.1/commons-io-2.16.1.jar",
16
+ "sha256": "f41f7baacd716896447ace9758621f62c1c6b0a91d89acee488da26fc477c84f",
17
+ "license": "Apache-2.0"
18
+ },
19
+ {
20
+ "purl": "pkg:maven/com.squareup.retrofit2/retrofit@2.9.0",
21
+ "repository": "maven-central",
22
+ "url": "https://repo.maven.apache.org/maven2/com/squareup/retrofit2/retrofit/2.9.0/retrofit-2.9.0.jar",
23
+ "sha256": "e6ea1929c46852f5bec66ab3357da383476cef4e8d1deefdbf195b79cc4d6581",
24
+ "license": "Apache-2.0"
25
+ },
26
+ {
27
+ "purl": "pkg:maven/com.squareup.retrofit2/converter-gson@2.9.0",
28
+ "repository": "maven-central",
29
+ "url": "https://repo.maven.apache.org/maven2/com/squareup/retrofit2/converter-gson/2.9.0/converter-gson-2.9.0.jar",
30
+ "sha256": "32aa206b9a29c9df5eda93a092cfb3b0b9133e232c062baa882f0319f0e79f0e",
31
+ "license": "Apache-2.0"
32
+ },
33
+ {
34
+ "purl": "pkg:maven/com.squareup.okhttp3/okhttp@4.9.0",
35
+ "repository": "maven-central",
36
+ "url": "https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp/4.9.0/okhttp-4.9.0.jar",
37
+ "sha256": "dbc2bb04ecb002b9f4046263ccad996f4a3d3c59a0cc98837e300a6700571f7c",
38
+ "license": "Apache-2.0"
39
+ },
40
+ {
41
+ "purl": "pkg:maven/com.squareup.okhttp3/okhttp@4.9.3",
42
+ "repository": "maven-central",
43
+ "url": "https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp/4.9.3/okhttp-4.9.3.jar",
44
+ "sha256": "93ecd6cba19d87dccfe566ec848d91aae799e3cf16c00709358ea69bd9227219",
45
+ "license": "Apache-2.0"
46
+ },
47
+ {
48
+ "purl": "pkg:maven/com.scottyab/rootbeer-lib@0.0.8",
49
+ "repository": "maven-central",
50
+ "url": "https://repo.maven.apache.org/maven2/com/scottyab/rootbeer-lib/0.0.8/rootbeer-lib-0.0.8.aar",
51
+ "sha256": "4750bedff6605ed4ca96e2dd9b13fd6216ba55eb7abf914cbd9f9f00566ad82a",
52
+ "license": "Apache-2.0"
53
+ },
54
+ {
55
+ "purl": "pkg:maven/com.squareup.okhttp3/okhttp@3.14.9",
56
+ "repository": "maven-central",
57
+ "url": "https://repo.maven.apache.org/maven2/com/squareup/okhttp3/okhttp/3.14.9/okhttp-3.14.9.jar",
58
+ "sha256": "2570fab55515cbf881d7a4ceef49fc515490bc027057e666776a2832465aeca0",
59
+ "license": "Apache-2.0",
60
+ "notes": "Targeted SCA validation against the dependency declared by Retrofit 2.9.0; not an installed-version claim"
61
+ }
62
+ ]
63
+ }
@@ -0,0 +1,51 @@
1
+ # Architecture
2
+
3
+ LibIdentifier is API-first. The CLI delegates to the same `identify()`, `inspect()`, `build_profile()`, and `export_cyclonedx()` functions exposed from `libidentifier`.
4
+
5
+ The scan pipeline is:
6
+
7
+ 1. Detect top-level format from magic bytes.
8
+ 2. Traverse ZIP/APK members with bounded, safe reads.
9
+ 3. Extract DEX class features and ELF identity features with LIEF. A bounded
10
+ standard DEX table reader supplies canonical descriptors, interface lists,
11
+ method references and code-item locations unavailable in LIEF's Python API.
12
+ 4. Convert features to deterministic fingerprints.
13
+ 5. Query a local read-only SQLite profile database.
14
+ 6. Score candidates conservatively and resolve location-aware ownership claims.
15
+ Conflicting claims, shape multiplicity ambiguity and duplicate descriptors
16
+ remain unattributed for component-edge aggregation.
17
+ 7. Extract structural/signature relationships and bounded explicit invocation
18
+ references; aggregate only uniquely attributed embedded endpoints.
19
+ 8. Group unmatched definitions deterministically by meaningful exact packages
20
+ and inheritance/interface links. Preserve singleton groups and unknown origin.
21
+ 9. Attach published reference declarations and supported embedded Maven version
22
+ metadata, reporting capability status, evidence, uncertainty and limitations.
23
+ 10. Emit deterministic JSON; unknown-output caps apply after enrichment.
24
+
25
+ The package has no dependency on any consuming application. Optional `scan()`/`correlate()` assessment
26
+ uses a verified local OSV executable and advisory snapshot. Python scan APIs never
27
+ download; the assessment CLI may provision a wholly absent database unless
28
+ `--offline`. Existing databases require explicit update. Assessment itself always
29
+ runs offline. Hosts retain application ownership, reachability and exploitability
30
+ decisions. See the [public contract](integration.md) and [roadmap](development/roadmap.md).
31
+
32
+ `extractors/instructions.py` traverses standard DEX widths and switch/array
33
+ payloads. Ordinary invoke/range forms yield declared references with absolute
34
+ member byte offsets; special dynamic formats and undecodable methods report
35
+ partial coverage. No runtime dispatch, execution, reachability or data-flow is
36
+ inferred. External/ambiguous targets have no embedded target location.
37
+
38
+ `profiles/pom.py` handles direct dependencies/local properties only. Parent,
39
+ BOM, dependency-management and profile context remains preserved but unresolved.
40
+ Source release declarations stay distinct from observed APK code references.
41
+ See [profile storage](profile-database.md) for internal schema/rebuild rules.
42
+
43
+
44
+ `cli_setup.py` is a CLI-only orchestration layer for managed scans without profile
45
+ overrides. It gathers missing resources, obtains one consent decision, invokes
46
+ explicit profile/advisory maintenance and installs a scanner pinned by
47
+ `cli_resources.py`. Scanner bytes are bounded and checked before execution.
48
+ The same pin catalog is used by native CI; no GitHub latest lookup occurs.
49
+ After setup the managed assessment path is forced offline, including when setup
50
+ was declined or failed. Existing explicit commands and analysis APIs keep their
51
+ previous resource policies.