├── .gitignore
├── LICENSE
├── README.md
├── androguard
├── LICENCE-2.0
├── __init__.py
└── core
│ ├── __init__.py
│ ├── analysis
│ ├── __init__.py
│ └── analysis.py
│ ├── bytecode.py
│ └── bytecodes
│ ├── __init__.py
│ ├── dvm.py
│ ├── dvm_types.py
│ └── mutf8.py
├── dcc.cfg
├── dcc.py
├── dex2c
├── __init__.py
├── basic_blocks.py
├── compiler.py
├── graph.py
├── instruction.py
├── opcode_ins.py
├── util.py
└── writer.py
├── filter.txt
├── keystore
└── debug.keystore
├── loader
└── DccApplication.smali
├── project
└── jni
│ ├── Android.mk
│ ├── Application.mk
│ └── nc
│ ├── Dex2C.cpp
│ ├── Dex2C.h
│ ├── DynamicRegister.h
│ ├── ScopedLocalRef.h
│ ├── ScopedPthreadMutexLock.h
│ ├── obfuscate.h
│ ├── well_known_classes.cpp
│ └── well_known_classes.h
├── requirements.txt
└── tools
├── APKEditor.jar
├── apksigner.jar
└── manifest-editor.jar
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by https://www.toptal.com/developers/gitignore/api/python
2 | # Edit at https://www.toptal.com/developers/gitignore?templates=python
3 |
4 | ### Python ###
5 | # Byte-compiled / optimized / DLL files
6 | __pycache__/
7 | *.py[cod]
8 | *$py.class
9 |
10 | # test apk, zip & signing files
11 | *.apk
12 | *.idsig
13 | *.zip
14 | tools/apktool.jar
15 |
16 | # C extensions
17 | *.so
18 |
19 | # Distribution / packaging
20 | .Python
21 | build/
22 | develop-eggs/
23 | dist/
24 | downloads/
25 | eggs/
26 | .eggs/
27 | lib/
28 | lib64/
29 | parts/
30 | sdist/
31 | var/
32 | wheels/
33 | share/python-wheels/
34 | *.egg-info/
35 | .installed.cfg
36 | *.egg
37 | MANIFEST
38 |
39 | # PyInstaller
40 | # Usually these files are written by a python script from a template
41 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
42 | *.manifest
43 | *.spec
44 |
45 | # Installer logs
46 | pip-log.txt
47 | pip-delete-this-directory.txt
48 |
49 | # Unit test / coverage reports
50 | htmlcov/
51 | .tox/
52 | .nox/
53 | .coverage
54 | .coverage.*
55 | .cache
56 | nosetests.xml
57 | coverage.xml
58 | *.cover
59 | *.py,cover
60 | .hypothesis/
61 | .pytest_cache/
62 | cover/
63 |
64 | # Translations
65 | *.mo
66 | *.pot
67 |
68 | # Django stuff:
69 | *.log
70 | local_settings.py
71 | db.sqlite3
72 | db.sqlite3-journal
73 |
74 | # Flask stuff:
75 | instance/
76 | .webassets-cache
77 |
78 | # Scrapy stuff:
79 | .scrapy
80 |
81 | # Sphinx documentation
82 | docs/_build/
83 |
84 | # PyBuilder
85 | .pybuilder/
86 | target/
87 |
88 | # Jupyter Notebook
89 | .ipynb_checkpoints
90 |
91 | # IPython
92 | profile_default/
93 | ipython_config.py
94 |
95 | # pyenv
96 | # For a library or package, you might want to ignore these files since the code is
97 | # intended to run in multiple environments; otherwise, check them in:
98 | # .python-version
99 |
100 | # pipenv
101 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
102 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
103 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
104 | # install all needed dependencies.
105 | #Pipfile.lock
106 |
107 | # poetry
108 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
109 | # This is especially recommended for binary packages to ensure reproducibility, and is more
110 | # commonly ignored for libraries.
111 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
112 | #poetry.lock
113 |
114 | # pdm
115 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
116 | #pdm.lock
117 | analyzer.py
118 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
119 | # in version control.
120 | # https://pdm.fming.dev/#use-with-ide
121 | .pdm.toml
122 |
123 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
124 | __pypackages__/
125 |
126 | # Celery stuff
127 | celerybeat-schedule
128 | celerybeat.pid
129 |
130 | # SageMath parsed files
131 | *.sage.py
132 |
133 | # Environments
134 | .env
135 | .venv
136 | env/
137 | venv/
138 | ENV/
139 | env.bak/
140 | venv.bak/
141 |
142 | # Spyder project settings
143 | .spyderproject
144 | .spyproject
145 |
146 | # Rope project settings
147 | .ropeproject
148 |
149 | # mkdocs documentation
150 | /site
151 |
152 | # mypy
153 | .mypy_cache/
154 | .dmypy.json
155 | dmypy.json
156 |
157 | # Pyre type checker
158 | .pyre/
159 |
160 | # pytype static type analyzer
161 | .pytype/
162 |
163 | # Cython debug symbols
164 | cython_debug/
165 |
166 | # PyCharm
167 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
168 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
169 | # and can be added to the global gitignore or merged into this file. For a more nuclear
170 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
171 | #.idea/
172 |
173 | ### Python Patch ###
174 | # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
175 | poetry.toml
176 |
177 | # ruff
178 | .ruff_cache/
179 |
180 | # LSP config files
181 | pyrightconfig.json
182 |
183 | # End of https://www.toptal.com/developers/gitignore/api/python
184 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://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,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
𝐃𝐞𝐱𝟐𝐂
3 |
4 | Method-based AOT compiler that can wrap Dalvik bytecode with JNI native code.
5 |
6 |
7 |
8 | ### Requierements
9 | 1. Python3
10 | 2. lxml python package.
11 | ```bash
12 | pip3 install -U --user 'lxml>=4.3.0'
13 | ```
14 | on Termux:
15 | ```bash
16 | pkg install libxml2 libxslt
17 | CFLAGS="-O0" pip install -U lxml
18 | ```
19 | 3. JRE/JDK
20 | 4. Android NDK
21 |
22 | ### Installation
23 | ```bash
24 | git clone https://github.com/Kirlif/d2c
25 | ```
26 | - configure dcc.cfg with your NDK path
27 |
28 | ### Major updates
29 | - changed Apktool for APKEditor
30 | - cleaned androguard from useless parts and removed dependencies
31 | - DEX file support: creates a ZIP archive of the built libraries and dex file
32 | - skip constructors by default
33 | - the application class is the loader ; if not defined or absent from dex, the custom loader is used
34 | - --allow-init option: do not skip constructors
35 | - --lib-name option: edit the library name, default: stub
36 | - --output default value is « output.apk » for an APK else « output.zip » for a DEX
37 | - --input only is required
38 | - all options can be configured in dcc.cfg ; options passed to the command line have priority
39 | - adjust APP_PLATFORM automatically
40 |
41 | ### Settings
42 |
43 | | Cli | Config | Default |
44 | | ----- | -------- | -------- |
45 | |-i, --input|||
46 | | -o, --output|output|output.(apk\|zip)|
47 | |-p, --obfuscate|obfuscate|false|
48 | |-d, --dynamic-register|dynamic_register|false|
49 | |-s, --skip-synthetic|skip_synthetic|false|
50 | |-a, --allow-init|allow_init|false|
51 | |-k, --force-keep-libs|force_keep_libs|false|
52 | |-b, --no-build|no_build|false|
53 | |-f, --filter|filter|filter.txt|
54 | |-c, --custom-loader|custom_loader|amimo.dcc.DccApplication|
55 | |-r, --force-custom-loader|force_custom_loader|false
56 | |-l, --lib-name|lib_name|stub|
57 | |-e, --source-dir|source_dir||
58 | |-z, --project-archive|project_archive|project-source.zip|
59 |
--------------------------------------------------------------------------------
/androguard/LICENCE-2.0:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
--------------------------------------------------------------------------------
/androguard/__init__.py:
--------------------------------------------------------------------------------
1 | # The current version of Androguard
2 | # Please use only this variable in any scripts,
3 | # to keep the version number the same everywhere.
4 | __version__ = "3.3.5"
5 |
--------------------------------------------------------------------------------
/androguard/core/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/androguard/core/analysis/__init__.py:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/androguard/core/analysis/analysis.py:
--------------------------------------------------------------------------------
1 | import re
2 | import warnings
3 | from androguard.core.bytecodes import dvm
4 | import logging
5 |
6 | log = logging.getLogger("androguard.analysis")
7 |
8 | BasicOPCODES = []
9 | for i in dvm.BRANCH_DVM_OPCODES:
10 | BasicOPCODES.append(re.compile(i))
11 |
12 |
13 | class DVMBasicBlock:
14 | """
15 | A simple basic block of a dalvik method
16 | """
17 |
18 | def __init__(self, start, vm, method, context):
19 | self.__vm = vm
20 | self.method = method
21 | self.context = context
22 |
23 | self.last_length = 0
24 | self.nb_instructions = 0
25 |
26 | self.fathers = []
27 | self.childs = []
28 |
29 | self.start = start
30 | self.end = self.start
31 |
32 | self.special_ins = {}
33 |
34 | self.name = "%s-BB@0x%x" % (self.method.get_name(), self.start)
35 | self.exception_analysis = None
36 |
37 | self.__cached_instructions = None
38 |
39 | def get_instructions(self):
40 | """
41 | Get all instructions from a basic block.
42 |
43 | :rtype: Return all instructions in the current basic block
44 | """
45 | tmp_ins = []
46 | idx = 0
47 | for i in self.method.get_instructions():
48 | if self.start <= idx < self.end:
49 | yield i
50 | idx += i.get_length()
51 |
52 | def get_nb_instructions(self):
53 | return self.nb_instructions
54 |
55 | def get_name(self):
56 | return "%s-BB@0x%x" % (self.method.get_name(), self.start)
57 |
58 | def get_start(self):
59 | return self.start
60 |
61 | def get_end(self):
62 | return self.end
63 |
64 | def get_last(self):
65 | return self.get_instructions()[-1]
66 |
67 | def get_next(self):
68 | """
69 | Get next basic blocks
70 |
71 | :rtype: a list of the next basic blocks
72 | """
73 | return self.childs
74 |
75 | def get_prev(self):
76 | """
77 | Get previous basic blocks
78 |
79 | :rtype: a list of the previous basic blocks
80 | """
81 | return self.fathers
82 |
83 | def set_fathers(self, f):
84 | self.fathers.append(f)
85 |
86 | def get_last_length(self):
87 | return self.last_length
88 |
89 | def set_childs(self, values):
90 | # print self, self.start, self.end, values
91 | if not values:
92 | next_block = self.context.get_basic_block(self.end + 1)
93 | if next_block is not None:
94 | self.childs.append((self.end - self.get_last_length(), self.end,
95 | next_block))
96 | else:
97 | for i in values:
98 | if i != -1:
99 | next_block = self.context.get_basic_block(i)
100 | if next_block is not None:
101 | self.childs.append((self.end - self.get_last_length(),
102 | i, next_block))
103 |
104 | for c in self.childs:
105 | if c[2] is not None:
106 | c[2].set_fathers((c[1], c[0], self))
107 |
108 | def push(self, i):
109 | self.nb_instructions += 1
110 | idx = self.end
111 | self.last_length = i.get_length()
112 | self.end += self.last_length
113 |
114 | op_value = i.get_op_value()
115 |
116 | if op_value == 0x26 or (0x2b <= op_value <= 0x2c):
117 | code = self.method.get_code().get_bc()
118 | self.special_ins[idx] = code.get_ins_off(idx + i.get_ref_off() * 2)
119 |
120 | def get_special_ins(self, idx):
121 | """
122 | Return the associated instruction to a specific instruction (for example a packed/sparse switch)
123 |
124 | :param idx: the index of the instruction
125 |
126 | :rtype: None or an Instruction
127 | """
128 | if idx in self.special_ins:
129 | return self.special_ins[idx]
130 | else:
131 | return None
132 |
133 | def get_exception_analysis(self):
134 | return self.exception_analysis
135 |
136 | def set_exception_analysis(self, exception_analysis):
137 | self.exception_analysis = exception_analysis
138 |
139 | class BasicBlocks:
140 | """
141 | This class represents all basic blocks of a method
142 | """
143 |
144 | def __init__(self, _vm):
145 | self.__vm = _vm
146 | self.bb = []
147 |
148 | def push(self, bb):
149 | self.bb.append(bb)
150 |
151 | def pop(self, idx):
152 | return self.bb.pop(idx)
153 |
154 | def get_basic_block(self, idx):
155 | for i in self.bb:
156 | if i.get_start() <= idx < i.get_end():
157 | return i
158 | return None
159 |
160 | def get(self):
161 | """
162 | :rtype: return each basic block (:class:`DVMBasicBlock` object)
163 | """
164 | for i in self.bb:
165 | yield i
166 |
167 | def gets(self):
168 | """
169 | :rtype: a list of basic blocks (:class:`DVMBasicBlock` objects)
170 | """
171 | return self.bb
172 |
173 | def get_basic_block_pos(self, idx):
174 | return self.bb[idx]
175 |
176 |
177 | class ExceptionAnalysis:
178 | def __init__(self, exception, bb):
179 | self.start = exception[0]
180 | self.end = exception[1]
181 |
182 | self.exceptions = exception[2:]
183 |
184 | for i in self.exceptions:
185 | i.append(bb.get_basic_block(i[1]))
186 |
187 | def show_buff(self):
188 | buff = "%x:%x\n" % (self.start, self.end)
189 |
190 | for i in self.exceptions:
191 | if i[2] is None:
192 | buff += "\t(%s -> %x %s)\n" % (i[0], i[1], i[2])
193 | else:
194 | buff += "\t(%s -> %x %s)\n" % (i[0], i[1], i[2].get_name())
195 |
196 | return buff[:-1]
197 |
198 | def get(self):
199 | d = {"start": self.start, "end": self.end, "list": []}
200 |
201 | for i in self.exceptions:
202 | d["list"].append({"name": i[0], "idx": i[1], "bb": i[2].get_name()})
203 |
204 | return d
205 |
206 |
207 | class Exceptions:
208 | def __init__(self, _vm):
209 | self.__vm = _vm
210 | self.exceptions = []
211 |
212 | def add(self, exceptions, basic_blocks):
213 | for i in exceptions:
214 | self.exceptions.append(ExceptionAnalysis(i, basic_blocks))
215 |
216 | def get_exception(self, addr_start, addr_end):
217 | for i in self.exceptions:
218 | if i.start >= addr_start and i.end <= addr_end:
219 | return i
220 |
221 | elif addr_end <= i.end and addr_start >= i.start:
222 | return i
223 |
224 | return None
225 |
226 | def gets(self):
227 | return self.exceptions
228 |
229 | def get(self):
230 | for i in self.exceptions:
231 | yield i
232 |
233 |
234 | class MethodAnalysis:
235 | def __init__(self, vm, method):
236 | """
237 | This class analyses in details a method of a class/dex file
238 | It is a wrapper around a :class:`EncodedMethod` and enhances it
239 | by using multiple :class:`BasicBlock`.
240 |
241 | :type vm: a :class:`DalvikVMFormat` object
242 | :type method: a :class:`EncodedMethod` object
243 | """
244 | self.__vm = vm
245 | self.method = method
246 |
247 | self.basic_blocks = BasicBlocks(self.__vm)
248 | self.exceptions = Exceptions(self.__vm)
249 |
250 | self.code = self.method.get_code()
251 | if self.code:
252 | self._create_basic_block()
253 |
254 | def _create_basic_block(self):
255 | current_basic = DVMBasicBlock(0, self.__vm, self.method, self.basic_blocks)
256 | self.basic_blocks.push(current_basic)
257 |
258 | bc = self.code.get_bc()
259 | l = []
260 | h = {}
261 | idx = 0
262 |
263 | log.debug("Parsing instructions")
264 | for i in bc.get_instructions():
265 | for j in BasicOPCODES:
266 | if j.match(i.get_name()) is not None:
267 | v = dvm.determineNext(i, idx, self.method)
268 | h[idx] = v
269 | l.extend(v)
270 | break
271 |
272 | idx += i.get_length()
273 |
274 | log.debug("Parsing exceptions")
275 | excepts = dvm.determineException(self.__vm, self.method)
276 | for i in excepts:
277 | l.extend([i[0]])
278 | for handler in i[2:]:
279 | l.append(handler[1])
280 |
281 | log.debug("Creating basic blocks in %s" % self.method)
282 | idx = 0
283 | for i in bc.get_instructions():
284 | # index is a destination
285 | if idx in l:
286 | if current_basic.get_nb_instructions() != 0:
287 | current_basic = DVMBasicBlock(current_basic.get_end(), self.__vm, self.method, self.basic_blocks)
288 | self.basic_blocks.push(current_basic)
289 |
290 | current_basic.push(i)
291 |
292 | # index is a branch instruction
293 | if idx in h:
294 | current_basic = DVMBasicBlock(current_basic.get_end(), self.__vm, self.method, self.basic_blocks)
295 | self.basic_blocks.push(current_basic)
296 |
297 | idx += i.get_length()
298 |
299 | if current_basic.get_nb_instructions() == 0:
300 | self.basic_blocks.pop(-1)
301 |
302 | log.debug("Settings basic blocks childs")
303 |
304 | for i in self.basic_blocks.get():
305 | try:
306 | i.set_childs(h[i.end - i.get_last_length()])
307 | except KeyError:
308 | i.set_childs([])
309 |
310 | log.debug("Creating exceptions")
311 |
312 | # Create exceptions
313 | self.exceptions.add(excepts, self.basic_blocks)
314 |
315 | for i in self.basic_blocks.get():
316 | # setup exception by basic block
317 | i.set_exception_analysis(self.exceptions.get_exception(i.start, i.end - 1))
318 |
319 | def get_basic_blocks(self):
320 | """
321 | :rtype: a :class:`BasicBlocks` object
322 | """
323 | return self.basic_blocks
324 |
325 | def get_length(self):
326 | """
327 | :rtype: an integer which is the length of the code
328 | """
329 | return self.code.get_length() if self.code else 0
330 |
331 | def get_method(self):
332 | return self.method
333 |
334 | def get_vm(self):
335 | return self.__vm
336 |
337 | class MethodClassAnalysis:
338 | def __init__(self, method):
339 | """
340 | MethodClassAnalysis contains the XREFs for a given method.
341 |
342 | Both referneces to other methods (XREF_TO) as well as methods calling
343 | this method (XREF_FROM) are saved.
344 |
345 | :param androguard.core.bytecodes.dvm.EncodedMethod method: the DVM Method object
346 | """
347 | self.method = method
348 |
349 |
350 | @property
351 | def name(self):
352 | """Returns the name of this method"""
353 | return self.method.get_name()
354 |
355 | @property
356 | def descriptor(self):
357 | """Returns the type descriptor for this method"""
358 | return self.method.get_descriptor()
359 |
360 | @property
361 | def access(self):
362 | """Returns the access flags to the method as a string"""
363 | return self.method.get_access_flags_string()
364 |
365 |
366 | class FieldClassAnalysis:
367 | def __init__(self, field):
368 | """
369 | FieldClassAnalysis contains the XREFs for a class field.
370 |
371 | Instead of using XREF_FROM/XREF_TO, this object has methods for READ and
372 | WRITE access to the field.
373 |
374 | That means, that it will show you, where the field is read or written.
375 |
376 | :param androguard.core.bytecodes.dvm.EncodedField field: `dvm.EncodedField`
377 | """
378 | self.field = field
379 |
380 | @property
381 | def name(self):
382 | return self.field.get_name()
383 |
384 | class ClassAnalysis:
385 | def __init__(self, classobj):
386 | """
387 | It is also used to wrap :class:`~androguard.core.bytecode.dvm.ClassDefItem`, which
388 | contain the actual class content like bytecode.
389 |
390 | :param classobj: class:`~androguard.core.bytecode.dvm.ClassDefItem`
391 | """
392 |
393 | self.orig_class = classobj
394 | self._methods = {}
395 | self._fields = {}
396 |
397 | @property
398 | def implements(self):
399 | """
400 | Get a list of interfaces which are implemented by this class
401 |
402 | :return: a list of Interface names
403 | """
404 | return self.orig_class.get_interfaces()
405 |
406 | @property
407 | def extends(self):
408 | """
409 | Return the parent class
410 |
411 | :return: a string of the parent class name
412 | """
413 | return self.orig_class.get_superclassname()
414 |
415 | @property
416 | def name(self):
417 | """
418 | Return the class name
419 |
420 | :return:
421 | """
422 | return self.orig_class.get_name()
423 |
424 | def get_vm_class(self):
425 | return self.orig_class
426 |
427 |
428 | class Analysis:
429 | def __init__(self, vm=None):
430 | """
431 | Analysis Object
432 |
433 | The Analysis contains a lot of information about (multiple) DalvikVMFormat objects
434 | Features are for example XREFs between Classes, Methods, Fields and Strings.
435 |
436 | Multiple DalvikVMFormat Objects can be added using the function `add`
437 |
438 | :param vm: inital DalvikVMFormat object (default None)
439 | """
440 |
441 | # Contains DalvikVMFormat objects
442 | self.vms = []
443 | # A dict of {classname: ClassAnalysis}, populated on add(vm)
444 | self.classes = {}
445 | # A dict of {EncodedMethod: MethodAnalysis}, populated on add(vm)
446 | self.methods = {}
447 |
448 | if vm:
449 | self.add(vm)
450 |
451 | def add(self, vm):
452 | """
453 | Add a DalvikVMFormat to this Analysis
454 |
455 | :param vm: :class:`dvm.DalvikVMFormat` to add to this Analysis
456 | """
457 | self.vms.append(vm)
458 | for current_class in vm.get_classes():
459 | self.classes[current_class.get_name()] = ClassAnalysis(current_class)
460 |
461 | for method in vm.get_methods():
462 | self.methods[method] = MethodAnalysis(vm, method)
463 |
464 | def get_method(self, method):
465 | """
466 | Get the :class:`MethodAnalysis` object for a given :class:`EncodedMethod`.
467 | This Analysis object is used to enhance EncodedMethods.
468 |
469 | :param method: :class:`EncodedMethod` to search for
470 | :return: :class:`MethodAnalysis` object for the given method, or None if method was not found
471 | """
472 | if method in self.methods:
473 | return self.methods[method]
474 | else:
475 | return None
476 |
--------------------------------------------------------------------------------
/androguard/core/bytecode.py:
--------------------------------------------------------------------------------
1 | from struct import unpack, pack
2 |
3 |
4 | # Print arg into a correct format
5 | def _Print(name, arg):
6 | buff = name + " "
7 |
8 | if type(arg).__name__ == 'int':
9 | buff += "0x%x" % arg
10 | elif type(arg).__name__ == 'long':
11 | buff += "0x%x" % arg
12 | elif type(arg).__name__ == 'str':
13 | buff += "%s" % arg
14 | elif isinstance(arg, SV):
15 | buff += "0x%x" % arg.get_value()
16 | print(buff)
17 |
18 | class SV(object):
19 |
20 | def __init__(self, size, buff):
21 | self.__size = size
22 | self.__value = unpack(self.__size, buff)[0]
23 |
24 | def _get(self):
25 | return pack(self.__size, self.__value)
26 |
27 | def __str__(self):
28 | return "0x%x" % self.__value
29 |
30 | def __int__(self):
31 | return self.__value
32 |
33 | def get_value_buff(self):
34 | return self._get()
35 |
36 | def get_value(self):
37 | return self.__value
38 |
39 | def set_value(self, attr):
40 | self.__value = attr
41 |
42 | def object_to_bytes(obj):
43 | """
44 | Convert a object to a bytearray or call get_raw() of the object
45 | if no useful type was found.
46 | """
47 | if isinstance(obj, str):
48 | return bytearray(obj, "UTF-8")
49 | elif isinstance(obj, bool):
50 | return bytearray()
51 | elif isinstance(obj, int):
52 | return pack("= len(self.__buff)
200 |
201 | def get_buff(self):
202 | """
203 | Return the whole buffer
204 |
205 | :rtype: bytearray
206 | """
207 | return self.__buff
208 |
209 | def set_buff(self, buff):
210 | """
211 | Overwrite the current buffer with the content of `buff`
212 |
213 | :param bytearray buff: the new buffer
214 | """
215 | self.__buff = buff
216 |
217 |
218 |
219 | class Buff(object):
220 | def __init__(self, offset, buff):
221 | self.offset = offset
222 | self.buff = buff
223 |
224 | self.size = len(buff)
225 |
226 |
227 | # Here for legacy reasons. Might get removed some day...
228 | _Bytecode = BuffHandle
229 |
230 |
231 | class Node(object):
232 | def __init__(self, n, s):
233 | self.id = n
234 | self.title = s
235 | self.children = []
236 |
237 |
--------------------------------------------------------------------------------
/androguard/core/bytecodes/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kirlif/d2c/80305482722efd38781d9213a7cc20b7bc036eed/androguard/core/bytecodes/__init__.py
--------------------------------------------------------------------------------
/androguard/core/bytecodes/dvm_types.py:
--------------------------------------------------------------------------------
1 | # This file contains dictionaries used in the Dalvik Format.
2 |
3 | # https://source.android.com/devices/tech/dalvik/dex-format#type-codes
4 | TYPE_MAP_ITEM = {
5 | 0x0: "TYPE_HEADER_ITEM",
6 | 0x1: "TYPE_STRING_ID_ITEM",
7 | 0x2: "TYPE_TYPE_ID_ITEM",
8 | 0x3: "TYPE_PROTO_ID_ITEM",
9 | 0x4: "TYPE_FIELD_ID_ITEM",
10 | 0x5: "TYPE_METHOD_ID_ITEM",
11 | 0x6: "TYPE_CLASS_DEF_ITEM",
12 | 0x1000: "TYPE_MAP_LIST",
13 | 0x1001: "TYPE_TYPE_LIST",
14 | 0x1002: "TYPE_ANNOTATION_SET_REF_LIST",
15 | 0x1003: "TYPE_ANNOTATION_SET_ITEM",
16 | 0x2000: "TYPE_CLASS_DATA_ITEM",
17 | 0x2001: "TYPE_CODE_ITEM",
18 | 0x2002: "TYPE_STRING_DATA_ITEM",
19 | 0x2003: "TYPE_DEBUG_INFO_ITEM",
20 | 0x2004: "TYPE_ANNOTATION_ITEM",
21 | 0x2005: "TYPE_ENCODED_ARRAY_ITEM",
22 | 0x2006: "TYPE_ANNOTATIONS_DIRECTORY_ITEM",
23 | }
24 |
25 | # https://source.android.com/devices/tech/dalvik/dex-format#access-flags
26 | ACCESS_FLAGS = {
27 | 0x1: 'public',
28 | 0x2: 'private',
29 | 0x4: 'protected',
30 | 0x8: 'static',
31 | 0x10: 'final',
32 | 0x20: 'synchronized',
33 | 0x40: 'bridge',
34 | 0x80: 'varargs',
35 | 0x100: 'native',
36 | 0x200: 'interface',
37 | 0x400: 'abstract',
38 | 0x800: 'strictfp',
39 | 0x1000: 'synthetic',
40 | 0x4000: 'enum',
41 | 0x8000: 'unused',
42 | 0x10000: 'constructor',
43 | 0x20000: 'synchronized',
44 | }
45 |
46 | # https://source.android.com/devices/tech/dalvik/dex-format#typedescriptor
47 | TYPE_DESCRIPTOR = {
48 | 'V': 'void',
49 | 'Z': 'boolean',
50 | 'B': 'byte',
51 | 'S': 'short',
52 | 'C': 'char',
53 | 'I': 'int',
54 | 'J': 'long',
55 | 'F': 'float',
56 | 'D': 'double',
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/androguard/core/bytecodes/mutf8.py:
--------------------------------------------------------------------------------
1 | import builtins
2 | from builtins import str
3 | import struct
4 |
5 |
6 | def chr(val):
7 | """
8 | Patched Version of builtins.chr, to work with narrow python builds
9 | In those versions, the function unichr does not work with inputs >0x10000
10 |
11 | This seems to be a problem usually on older windows builds.
12 |
13 | :param val: integer value of character
14 | :return: character
15 | """
16 | try:
17 | return builtins.chr(val)
18 | except ValueError as e:
19 | if "(narrow Python build)" in str(e):
20 | return struct.pack('i', val).decode('utf-32')
21 | else:
22 | raise e
23 |
24 |
25 | def decode(b):
26 | """
27 | Decode bytes as MUTF-8
28 | See https://docs.oracle.com/javase/6/docs/api/java/io/DataInput.html#modified-utf-8
29 | for more information
30 |
31 | Surrogates will be returned as two 16 bit characters.
32 |
33 | :param b: bytes to decode
34 | :rtype: unicode (py2), str (py3) of 16bit chars
35 | :raises: UnicodeDecodeError if string is not decodable
36 | """
37 | res = u""
38 |
39 | b = iter(bytearray(b))
40 |
41 | for x in b:
42 | if x >> 7 == 0:
43 | # Single char:
44 | res += chr(x & 0x7f)
45 | elif x >> 5 == 0b110:
46 | # 2 byte Multichar
47 | b2 = next(b)
48 | if b2 >> 6 != 0b10:
49 | raise UnicodeDecodeError("Second byte of 2 byte sequence does not looks right.")
50 |
51 | res += chr((x & 0x1f) << 6 | b2 & 0x3f)
52 | elif x >> 4 == 0b1110:
53 | # 3 byte Multichar
54 | b2 = next(b)
55 | b3 = next(b)
56 | if b2 >> 6 != 0b10:
57 | raise UnicodeDecodeError("Second byte of 3 byte sequence does not looks right.")
58 | if b3 >> 6 != 0b10:
59 | raise UnicodeDecodeError("Third byte of 3 byte sequence does not looks right.")
60 |
61 | res += chr((x & 0xf) << 12 | (b2 & 0x3f) << 6 | b3 & 0x3f)
62 | else:
63 | raise UnicodeDecodeError("Could not decode byte")
64 |
65 | return res
66 |
67 |
68 | class PeekIterator:
69 | """
70 | A quick'n'dirty variant of an Iterator that has a special function
71 | peek, which will return the next object but not consume it.
72 | """
73 | idx = 0
74 |
75 | def __init__(self, s):
76 | self.s = s
77 |
78 | def __iter__(self):
79 | return self
80 |
81 | def __next__(self):
82 | if self.idx == len(self.s):
83 | raise StopIteration()
84 | self.idx = self.idx + 1
85 | return self.s[self.idx - 1]
86 |
87 | def next(self):
88 | # py2 compliance
89 | return self.__next__()
90 |
91 | def peek(self):
92 | if self.idx == len(self.s):
93 | return None
94 | return self.s[self.idx]
95 |
96 |
97 | def patch_string(s):
98 | """
99 | Reorganize a String in such a way that surrogates are printable
100 | and lonely surrogates are escaped.
101 |
102 | :param s: input string
103 | :return: string with escaped lonely surrogates and 32bit surrogates
104 | """
105 | res = u''
106 | it = PeekIterator(s)
107 | for c in it:
108 | if (ord(c) >> 10) == 0b110110:
109 | # High surrogate
110 | # Check for the next
111 | n = it.peek()
112 | if n and (ord(n) >> 10) == 0b110111:
113 | # Next is a low surrogate! Merge them together
114 | res += chr(((ord(c) & 0x3ff) << 10 | (ord(n) & 0x3ff)) + 0x10000)
115 | # Skip next char, as we already consumed it
116 | next(it)
117 | else:
118 | # Lonely high surrogate
119 | res += u"\\u{:04x}".format(ord(c))
120 | elif (ord(c) >> 10) == 0b110111:
121 | # Lonely low surrogate
122 | res += u"\\u{:04x}".format(ord(c))
123 | else:
124 | # Looks like a normal char...
125 | res += c
126 | return res
127 |
128 |
--------------------------------------------------------------------------------
/dcc.cfg:
--------------------------------------------------------------------------------
1 | {
2 | "ndk_dir": "path/to/ndkdir",
3 | "signature": {
4 | "keystore_path": "keystore/debug.keystore",
5 | "alias": "androiddebugkey",
6 | "keystore_pass": "android",
7 | "store_pass": "android",
8 | "v1_enabled": true,
9 | "v2_enabled": true,
10 | "v3_enabled": true
11 | },
12 | "output": "",
13 | "obfuscate": false,
14 | "dynamic_register": false,
15 | "skip_synthetic": false,
16 | "allow_init": false,
17 | "force_keep_libs": false,
18 | "no_build": false,
19 | "filter": "filter.txt",
20 | "custom_loader": "amimo.dcc.DccApplication",
21 | "force_custom_loader": false,
22 | "lib_name": "stub",
23 | "source_dir": "",
24 | "project_archive": "project-source.zip"
25 | }
26 |
--------------------------------------------------------------------------------
/dex2c/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kirlif/d2c/80305482722efd38781d9213a7cc20b7bc036eed/dex2c/__init__.py
--------------------------------------------------------------------------------
/dex2c/basic_blocks.py:
--------------------------------------------------------------------------------
1 | # encoding=utf8
2 | #
3 | # Copyright (c) 2012 Geoffroy Gueguen
4 | # All Rights Reserved.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS-IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | import logging
19 | from builtins import object
20 | from collections import OrderedDict
21 |
22 | from dex2c.instruction import MoveResultExpression
23 | from dex2c.opcode_ins import INSTRUCTION_SET
24 |
25 | logger = logging.getLogger('dex2c.basic_blocks')
26 |
27 |
28 | class IrBasicBlock(object):
29 | def __init__(self, dvm_basicblock):
30 | self.dvm_basicblock = dvm_basicblock
31 | self.instr_list = []
32 |
33 | # MoveParam指令会给参数生成一个局部引用(local reference), 使用局部引用引用参数
34 | # 不能将它放入instr_list, 因为第一个基本块可以是循环
35 | self.move_param_insns = []
36 | self.var_to_declare = list()
37 | self.class_to_declare = list()
38 | self.field_to_declare = list()
39 | self.method_to_declare = list()
40 | self.num = -1 # 基本块编号
41 |
42 | # 处理异常相关
43 | self.in_catch = False
44 | self.catch_type = None
45 |
46 | # 构建SSA IR使用数据结构
47 | # Ref: <> by Matthias Braun
48 | self.filled = False
49 | self.sealed = False
50 | self.current_definitions = {}
51 | self.incomplete_phis = set()
52 | self.phis = set()
53 |
54 | self.catch_successors = set()
55 |
56 | if dvm_basicblock:
57 | self.start = self.dvm_basicblock.get_start()
58 | else:
59 | self.start = -1
60 |
61 | def get_instr_list(self):
62 | return self.instr_list
63 |
64 | def get_name(self):
65 | return self.label
66 |
67 | def add_ins_before(self, new_ins, before_ins):
68 | pos = self.instr_list.index(before_ins)
69 | self.instr_list = self.instr_list[:pos] + [new_ins] + self.instr_list[pos:]
70 |
71 | def remove_ins(self, ins):
72 | self.instr_list.remove(ins)
73 |
74 | def add_ins(self, new_ins):
75 | self.instr_list.append(new_ins)
76 |
77 | def add_variable_declaration(self, variable):
78 | self.var_to_declare.append(variable)
79 |
80 | def set_catch_type(self, _type):
81 | self.catch_type = _type
82 |
83 | def update_current_definition(self, register, var):
84 | self.current_definitions[register] = var
85 |
86 | def read_current_definition(self, register):
87 | return self.current_definitions[register] if register in self.current_definitions else None
88 |
89 | def visit(self, visitor):
90 | # pass
91 | visitor.visit_statement_node(self)
92 |
93 | def add_incomplete_phi(self, phi):
94 | self.incomplete_phis.add(phi)
95 |
96 | def get_incomplete_phis(self):
97 | return self.incomplete_phis
98 |
99 | def clear_incomplete_phis(self):
100 | self.incomplete_phis.clear()
101 |
102 | def add_phi(self, phi):
103 | self.phis.add(phi)
104 |
105 | def remove_phi(self, phi):
106 | if phi in self.phis:
107 | self.phis.remove(phi)
108 |
109 | def clear_phis(self):
110 | self.phis.clear()
111 |
112 | def add_catch_successor(self, node):
113 | if node not in self.catch_successors:
114 | self.catch_successors.add(node)
115 |
116 | @property
117 | def label(self):
118 | if self.dvm_basicblock:
119 | return 'BB_%x' % self.dvm_basicblock.start
120 | else:
121 | return 'BB_%d' % self.num
122 |
123 | def __str__(self):
124 | s = [self.label]
125 | for phi in self.phis:
126 | s.append(phi.print())
127 |
128 | for ins in self.instr_list:
129 | s.append(str(ins))
130 | return '\n'.join(s)
131 |
132 |
133 | class LandingPad(IrBasicBlock):
134 | def __init__(self, source):
135 | super(LandingPad, self).__init__(None)
136 | self.node = source
137 | self.handles = OrderedDict()
138 |
139 | def add_catch_handle(self, atype, node):
140 | if atype in self.handles and atype != 'Ljava/lang/Throwable;':
141 | raise Exception("duplicate catch handle for %s" % atype)
142 |
143 | if atype not in self.handles:
144 | self.handles[atype] = node
145 |
146 | @property
147 | def label(self):
148 | return 'EX_LandingPad_%d' % self.node.num
149 |
150 | def __str__(self):
151 | return '%d' % self.node.num
152 |
153 |
154 | def fill_node_from_block(irbuilder, node):
155 | block = node.dvm_basicblock
156 | idx = block.get_start()
157 | current_node = node
158 | for ins in block.get_instructions():
159 | opcode = ins.get_op_value()
160 | if opcode == -1: # FIXME? or opcode in (0x0300, 0x0200, 0x0100):
161 | idx += ins.get_length()
162 | continue
163 | try:
164 | _ins = INSTRUCTION_SET[opcode]
165 | except IndexError:
166 | raise Exception('Unknown instruction : %s.', ins.get_name().lower())
167 | # fill-array-data
168 | if opcode == 0x26:
169 | fillarray = block.get_special_ins(idx)
170 | lastins = _ins(ins, irbuilder, fillarray)
171 | current_node.add_ins(lastins)
172 | # invoke-kind[/range]
173 | elif 0x6e <= opcode <= 0x72 or 0x74 <= opcode <= 0x78:
174 | lastins = _ins(ins, irbuilder)
175 | current_node.add_ins(lastins)
176 | elif 0x24 <= opcode <= 0x25:
177 | lastins = _ins(ins, irbuilder)
178 | current_node.add_ins(lastins)
179 | # move-result*
180 | elif 0xa <= opcode <= 0xc:
181 | lastins = _ins(ins, irbuilder)
182 | current_node.add_ins(lastins)
183 | # move-exception
184 | elif opcode == 0xd:
185 | lastins = _ins(ins, irbuilder, current_node.catch_type)
186 | current_node.add_ins(lastins)
187 | # {packed,sparse}-switch
188 | elif 0x2b <= opcode <= 0x2c:
189 | values = block.get_special_ins(idx)
190 | lastins = _ins(ins, irbuilder, values)
191 | current_node.add_ins(lastins)
192 | else:
193 | lastins = _ins(ins, irbuilder)
194 | current_node.add_ins(lastins)
195 | # aget-object v1_y, v1_x, v0
196 | # 如果v1_x在该指令后不再使用,我们会将v1_x释放,但是v1_x,v1_y分配到同一个寄存器(v1),导致v1_y被释放.
197 | # 解决办法是,我们将其转化为两条指令
198 | # aget-object vTmp, v1, v0
199 | # move-result-object v1, vTmp
200 | # 类似iget-object
201 | if opcode == 0x46 or opcode == 0x54:
202 | vtmp = irbuilder.write_result_variable()
203 | val = lastins.get_value()
204 | lastins.set_value(vtmp)
205 | move_ins = MoveResultExpression(val, vtmp)
206 | move_ins.parent = current_node # 变量活跃分析会使用
207 | current_node.add_ins(move_ins)
208 | lastins.offset = idx
209 | lastins.parent = current_node
210 | if lastins.get_value():
211 | lastins.get_value().definition = lastins
212 |
213 | idx += ins.get_length()
214 | lastins.next_offset = idx
215 | lastins.dvm_instr = ins
216 |
217 | current_node.filled = True
218 | return current_node
219 |
--------------------------------------------------------------------------------
/dex2c/compiler.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | #
4 | # Copyright (c) 2012 Geoffroy Gueguen
5 | # All Rights Reserved.
6 | #
7 | # Licensed under the Apache License, Version 2.0 (the "License");
8 | # you may not use this file except in compliance with the License.
9 | # You may obtain a copy of the License at
10 | #
11 | # http://www.apache.org/licenses/LICENSE-2.0
12 | #
13 | # Unless required by applicable law or agreed to in writing, software
14 | # distributed under the License is distributed on an "AS-IS" BASIS,
15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | # See the License for the specific language governing permissions and
17 | # limitations under the License.
18 | from dex2c.basic_blocks import fill_node_from_block
19 |
20 | import logging
21 | from collections import defaultdict
22 | import dex2c.util as util
23 | from androguard.core.analysis import analysis
24 | from dex2c.graph import construct
25 | from dex2c.instruction import Param, ThisParam, MoveParam, Phi, Variable, LoadConstant
26 | from dex2c.writer import Writer
27 |
28 | DEBUG = False
29 | # DEBUG = True
30 |
31 | logger = logging.getLogger("dex2c.compiler")
32 |
33 |
34 | class RegisterAllocator(object):
35 | def __init__(self, vars):
36 | self.slots = {}
37 | self.next_name = 0
38 | for var in vars:
39 | self.allocate(var)
40 |
41 | def allocate(self, var):
42 | register = var.get_register()
43 | assert var.get_type()
44 | atype = util.get_cdecl_type(var.get_type())
45 | if (register, atype) not in self.slots:
46 | logger.debug("%s -> v%s:%s" % (var, self.next_name, atype))
47 | self.slots[(register, atype)] = self.next_name
48 | self.next_name += 1
49 | else:
50 | logger.debug("%s -> v%s:%s" % (var, self.slots[(register, atype)], atype))
51 | return self.slots[(register, atype)]
52 |
53 |
54 | class IrMethod(object):
55 | def __init__(self, graph, method):
56 | self.method = method
57 |
58 | self.graph = graph
59 | self.entry = graph.entry
60 | self.offset_to_node = graph.offset_to_node
61 | self.node_to_landing_pad = graph.node_to_landing_pad
62 | self.landing_pads = graph.landing_pads
63 | self.irblocks = self.graph.compute_block_order()
64 |
65 | self.cls_name = method.get_class_name()
66 | self.name = method.get_name()
67 | self.ra = RegisterAllocator(self.entry.var_to_declare).allocate
68 | self.writer = None
69 |
70 | self.rtype = None
71 | self.params = []
72 | self.params_type = []
73 |
74 | def show_source(self):
75 | print(self.get_source())
76 |
77 | def get_source(self):
78 | if self.writer:
79 | return str(self.writer)
80 | return ""
81 |
82 | def get_prototype(self):
83 | if self.writer:
84 | return self.writer.get_prototype()
85 | return ''
86 |
87 | def __repr__(self):
88 | return "class IrMethod(object): %s" % self.name
89 |
90 |
91 | class IrBuilder(object):
92 | def __init__(self, methanalysis, obfus, dynamic_register):
93 | method = methanalysis.get_method()
94 | self.method = method
95 | self.irmethod = None
96 | self.start_block = next(methanalysis.get_basic_blocks().get(), None)
97 | self.cls_name = method.get_class_name()
98 | self.name = method.get_name()
99 | self.lparams = []
100 | self.var_to_name = defaultdict()
101 | self.offset_to_node = {}
102 | self.graph = None
103 | self.dynamic_register = dynamic_register
104 |
105 | self.access = util.get_access_method(method.get_access_flags())
106 |
107 | desc = method.get_descriptor()
108 | self.type = desc.split(")")[-1]
109 | self.params_type = util.get_params_type(desc)
110 | self.triple = method.get_triple()
111 |
112 | self.exceptions = methanalysis.exceptions.exceptions
113 | self.curret_block = None
114 |
115 | self.var_versions = defaultdict(int)
116 |
117 | self.obfus = obfus
118 |
119 | code = self.method.get_code()
120 | if code:
121 | start = code.registers_size - code.ins_size
122 | if "static" not in self.access:
123 | self.lparams.append(start)
124 | start += 1
125 | num_param = 0
126 | for ptype in self.params_type:
127 | param = start + num_param
128 | self.lparams.append(param)
129 | num_param += util.get_type_size(ptype)
130 |
131 | def get_return_type(self):
132 | return self.type
133 |
134 | def process(self):
135 | logger.debug("METHOD : %s", self.name)
136 |
137 | # Native methods... no blocks.
138 | if self.start_block is None:
139 | return
140 |
141 | graph = construct(self.start_block)
142 | self.graph = graph
143 |
144 | self.build()
145 |
146 | irmethod = IrMethod(graph, self.method)
147 | irmethod.rtype = self.get_return_type()
148 | irmethod.params = self.lparams
149 | irmethod.params_type = self.params_type
150 |
151 | writer = Writer(irmethod, self.dynamic_register)
152 | writer.write_method()
153 | irmethod.writer = writer
154 | return irmethod
155 |
156 | def build(self):
157 | self.define_params()
158 |
159 | self.graph.entry.sealed = True # Entry has Predecessor?
160 |
161 | todo = [self.graph.entry]
162 | while todo:
163 | node = todo.pop(0)
164 | if node.filled:
165 | continue
166 | self.curret_block = node
167 | node = fill_node_from_block(self, node)
168 | self.try_seal_block(node)
169 | todo.extend(self.graph.all_sucs(node))
170 |
171 | self.remove_trivial_phi()
172 |
173 | self.hack_polymorphic_constant()
174 |
175 | self.infer_type()
176 | self.fix_const_type()
177 | self.verify_operand_type()
178 | self.verify_phi_operand_type()
179 |
180 | # self.dump_type()
181 |
182 | self.add_var_to_decl()
183 |
184 | def remove_trivial_phi(self):
185 | Changed = True
186 | while Changed:
187 | Changed = False
188 | for node in self.graph.rpo:
189 | phis = list(node.phis)
190 | for phi in phis:
191 | Changed |= phi.remove_trivial_phi()
192 |
193 | def verify_operand_type(self):
194 | nodes = self.graph.compute_block_order()
195 | for node in nodes:
196 | for ins in node.get_instr_list():
197 | var = ins.get_value()
198 | if var and var.get_type() is None:
199 | raise Exception("unkonw type %s" % var)
200 |
201 | def verify_phi_operand_type(self):
202 | for node in self.graph.rpo:
203 | phis = list(node.phis)
204 | for phi in phis:
205 | same_type = phi.get_type()
206 | for operand in phi.get_operands().values():
207 | op_type = operand.get_type()
208 | if util.is_int(same_type) and util.is_int(op_type):
209 | continue
210 | elif util.is_float(same_type) and util.is_float(op_type):
211 | continue
212 | elif util.is_ref(same_type) and util.is_ref(op_type):
213 | continue
214 | else:
215 | raise Exception(
216 | "inconsistency phi operand type %s %s %s"
217 | % (phi, same_type, op_type)
218 | )
219 |
220 | def hack_polymorphic_constant(self):
221 | nodes = self.graph.compute_block_order()
222 | todo_list = []
223 | for node in nodes:
224 | for ins in node.get_instr_list():
225 | if isinstance(ins, LoadConstant) and ins.get_value_type() is None:
226 | todo_list.append(ins)
227 | while todo_list:
228 | ins = todo_list.pop(0)
229 | bb = ins.parent
230 | for user in ins.get_users():
231 | new_val = self.write_variable(ins.get_value().get_register())
232 | new_ins = LoadConstant(new_val, ins.get_cst())
233 | bb.add_ins_before(new_ins, ins)
234 | # 每处引用不同的常量拷贝,解决常量多态问题.如0,可以当NULL,整型0,false使用.
235 | user.replase_use_of_with(ins.get_value(), new_val)
236 | ins.parent.remove_ins(ins)
237 |
238 | def infer_type(self):
239 | Changed = True
240 | nodes = self.graph.compute_block_order()
241 | max = 500
242 | while Changed:
243 | # self.dump_type()
244 | max -= 1
245 | if max == 0:
246 | raise Exception("type infer failed")
247 |
248 | Changed = False
249 | for node in nodes:
250 | for phi in node.phis:
251 | Changed |= phi.resolve_type()
252 | for ins in node.get_instr_list():
253 | Changed |= ins.resolve_type()
254 |
255 | # 无法推导出的常量类型,根据其大小,设置类型
256 | def fix_const_type(self):
257 | nodes = self.graph.rpo
258 | Changed = False
259 | for node in nodes:
260 | for ins in node.get_instr_list():
261 | if isinstance(ins, LoadConstant) and ins.get_value_type() is None:
262 | if -2147483648 <= ins.get_cst().get_constant() <= 2147483647:
263 | Changed = True
264 | logger.debug("Set constant type to int: %s" % ins)
265 | ins.set_value_type("I")
266 | else:
267 | Changed = True
268 | logger.debug("Set constant type to long: %s" % ins)
269 | ins.set_value_type("J")
270 |
271 | if Changed:
272 | self.infer_type()
273 |
274 | def dump_type(self):
275 | nodes = self.graph.compute_block_order()
276 | for node in nodes:
277 | for ins in node.get_instr_list():
278 | var = ins.get_value()
279 | if var is not None:
280 | print("Type: %s %s" % (var, var.get_type()))
281 |
282 | def add_var_to_decl(self):
283 | entry = self.graph.entry
284 | nodes = self.graph.compute_block_order()
285 | for node in nodes:
286 | for ins in node.get_instr_list():
287 | var = ins.get_value()
288 | if var is not None:
289 | entry.var_to_declare.append(var)
290 |
291 | clz = ins.get_class()
292 | if clz:
293 | entry.class_to_declare.append(clz)
294 |
295 | field = ins.get_field()
296 | if field:
297 | entry.field_to_declare.append(field)
298 |
299 | method = ins.get_call_method()
300 | if method:
301 | entry.method_to_declare.append(method)
302 |
303 | def try_seal_block(self, block):
304 | sucs = self.graph.all_sucs(block)
305 |
306 | if len(sucs) == 0:
307 | return
308 |
309 | for suc in sucs:
310 | preds = self.graph.all_preds(suc)
311 | filled = list(filter(lambda pred: pred.filled, preds))
312 | if len(filled) == len(preds):
313 | self.seal_block(suc)
314 |
315 | def seal_block(self, block):
316 | preds = self.graph.all_preds(block)
317 | block.sealed = True
318 | for phi in block.get_incomplete_phis():
319 | for pred in preds:
320 | incoming = self.read_variable(phi.get_register(), pred)
321 | phi.add_operand(pred, incoming)
322 | block.add_phi(phi)
323 | block.clear_incomplete_phis()
324 |
325 | def set_current_block(self, block):
326 | self.curret_block = block
327 |
328 | def get_current_block(self):
329 | return self.curret_block
330 |
331 | def read_result_variable(self):
332 | var = self.read_variable(-1, self.curret_block)
333 | if isinstance(var, Phi):
334 | raise Exception("invoke result is a Phi node")
335 | return var
336 |
337 | def write_result_variable(self):
338 | return self.write_variable(-1)
339 |
340 | def write_variable(self, register):
341 | value = self.new_ssa_variable(register)
342 | self.curret_block.update_current_definition(register, value)
343 | return value
344 |
345 | def read_variable(self, register, block=None):
346 | if block is None:
347 | block = self.curret_block
348 | value = block.read_current_definition(register)
349 | if value is None:
350 | return self.read_variable_recursive(register, block)
351 | else:
352 | return value
353 |
354 | def read_variable_recursive(self, register, block):
355 | preds = self.graph.all_preds(block)
356 | if not block.sealed:
357 | value = self.new_ssa_variable(register, True)
358 | block.add_incomplete_phi(value)
359 | value.set_block(block)
360 | elif len(preds) == 1:
361 | value = self.read_variable(register, preds[0])
362 | else:
363 | value = self.new_ssa_variable(register, True)
364 | block.update_current_definition(register, value)
365 | block.add_phi(value)
366 | value.set_block(block)
367 | for pred in preds:
368 | incoming = self.read_variable(register, pred)
369 | value.add_operand(pred, incoming)
370 | block.update_current_definition(register, value)
371 | return value
372 |
373 | def define_params(self):
374 | entry = self.graph.entry
375 | code = self.method.get_code()
376 | if code:
377 | start = code.registers_size - code.ins_size
378 | if "static" not in self.access:
379 | param = self.new_ssa_variable(start)
380 | param.set_type(self.cls_name)
381 | entry.move_param_insns.append(MoveParam(ThisParam(param)))
382 | entry.update_current_definition(start, param)
383 | entry.var_to_declare.append(param)
384 | start += 1
385 | num_param = 0
386 | for ptype in self.params_type:
387 | register = start + num_param
388 | param = self.new_ssa_variable(register)
389 | param.set_type(ptype)
390 | entry.move_param_insns.append(MoveParam(Param(param)))
391 | entry.update_current_definition(register, param)
392 | entry.var_to_declare.append(param)
393 | num_param += util.get_type_size(ptype)
394 |
395 | def new_ssa_variable(self, register, phi=False):
396 | ver = self.var_versions.get(register, 0)
397 | new_var = Phi(register, ver) if phi else Variable(register, ver)
398 |
399 | ver += 1
400 | self.var_versions[register] = ver
401 | return new_var
402 |
403 | def __repr__(self):
404 | # return 'Method %s' % self.name
405 | return "class DvMethod(object): %s" % self.name
406 |
407 |
408 | class DvClass(object):
409 | def __init__(self, dvclass, vma):
410 | name = dvclass.get_name()
411 | if name.find("/") > 0:
412 | pckg, name = name.rsplit("/", 1)
413 | else:
414 | pckg, name = "", name
415 | self.package = pckg[1:].replace("/", ".")
416 | self.name = name[:-1]
417 |
418 | self.vma = vma
419 | self.methods = dvclass.get_methods()
420 | self.fields = dvclass.get_fields()
421 | self.code = []
422 | self.inner = False
423 |
424 | access = dvclass.get_access_flags()
425 | # If interface we remove the class and abstract keywords
426 | if 0x200 & access:
427 | prototype = "%s %s"
428 | if access & 0x400:
429 | access -= 0x400
430 | else:
431 | prototype = "%s class %s"
432 |
433 | self.access = util.get_access_class(access)
434 | self.prototype = prototype % (" ".join(self.access), self.name)
435 |
436 | self.interfaces = dvclass.get_interfaces()
437 | self.superclass = dvclass.get_superclassname()
438 | self.thisclass = dvclass.get_name()
439 |
440 | logger.info("Class : %s", self.name)
441 | logger.info("Methods added :")
442 | for meth in self.methods:
443 | logger.info("%s (%s, %s)", meth.get_method_idx(), self.name, meth.name)
444 | logger.info("")
445 |
446 | def get_methods(self):
447 | return self.methods
448 |
449 | def process_method(self, num):
450 | method = self.methods[num]
451 | if not isinstance(method, IrMethod):
452 | irbuilder = IrBuilder(self.vma.get_method(method))
453 | self.methods[num] = irbuilder.process()
454 | else:
455 | method.process()
456 |
457 | def process(self):
458 | for i in range(len(self.methods)):
459 | try:
460 | self.process_method(i)
461 | except Exception as e:
462 | logger.warning("Error decompiling method %s: %s", self.methods[i], e)
463 |
464 | def get_source(self):
465 | source = []
466 | for method in self.methods:
467 | if isinstance(method, IrMethod):
468 | source.append(method.get_source())
469 | return "".join(source)
470 |
471 | def show_source(self):
472 | print(self.get_source())
473 |
474 | def __repr__(self):
475 | return "Class(%s)" % self.name
476 |
477 |
478 | class Dex2C:
479 | def __init__(self, vm, vmx, obfus, dynamic_register):
480 | self.vm = vm
481 | self.vmx = vmx
482 | self.obfus = obfus
483 | self.dynamic_register = dynamic_register
484 |
485 |
486 | def get_source_method(self, m):
487 | mx = self.vmx.get_method(m)
488 | z = IrBuilder(mx, self.obfus, self.dynamic_register)
489 | irmethod = z.process()
490 | if irmethod:
491 | return (irmethod.get_source(), irmethod.get_prototype())
492 | else:
493 | return (None, None)
494 |
495 | def get_source_class(self, _class):
496 | c = DvClass(_class, self.vmx)
497 | c.process()
498 | return c.get_source()
499 |
--------------------------------------------------------------------------------
/dex2c/graph.py:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (c) 2012 Geoffroy Gueguen
3 | # All Rights Reserved.
4 | #
5 | # Licensed under the Apache License, Version 2.0 (the "License");
6 | # you may not use this file except in compliance with the License.
7 | # You may obtain a copy of the License at
8 | #
9 | # http://www.apache.org/licenses/LICENSE-2.0
10 | #
11 | # Unless required by applicable law or agreed to in writing, software
12 | # distributed under the License is distributed on an "AS-IS" BASIS,
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | # See the License for the specific language governing permissions and
15 | # limitations under the License.
16 | from collections import defaultdict
17 |
18 | from dex2c.basic_blocks import (IrBasicBlock, LandingPad)
19 | from dex2c.instruction import *
20 |
21 | logger = logging.getLogger('dex2c.graph')
22 |
23 |
24 | class Graph(object):
25 | def __init__(self):
26 | self.entry = None
27 | self.exit = None
28 | self.nodes = list()
29 | self.landing_pads = list()
30 | self.rpo = []
31 | self.edges = defaultdict(list)
32 | self.catch_edges = defaultdict(list)
33 | self.reverse_edges = defaultdict(list)
34 | self.reverse_catch_edges = defaultdict(list)
35 | self.loc_to_ins = None
36 | self.loc_to_node = None
37 | self.offset_to_node = {}
38 | self.node_to_landing_pad = {}
39 |
40 | def sucs(self, node):
41 | return self.edges.get(node, [])[:]
42 |
43 | def all_sucs(self, node):
44 | return self.edges.get(node, []) + self.catch_edges.get(node, [])
45 |
46 | def all_catches(self, node):
47 | return self.catch_edges.get(node, [])[:]
48 |
49 | def preds(self, node):
50 | return [n for n in self.reverse_edges.get(node, []) if not n.in_catch]
51 |
52 | def all_preds(self, node):
53 | return (self.reverse_edges.get(node, []) + self.reverse_catch_edges.get(
54 | node, []))
55 |
56 | def add_node(self, node):
57 | self.nodes.append(node)
58 |
59 | def add_landing_pad(self, pad):
60 | self.landing_pads.append(pad)
61 |
62 | def add_edge(self, e1, e2):
63 | lsucs = self.edges[e1]
64 | if e2 not in lsucs:
65 | lsucs.append(e2)
66 | lpreds = self.reverse_edges[e2]
67 | if e1 not in lpreds:
68 | lpreds.append(e1)
69 |
70 | def remove_edge(self, e1, e2):
71 | lsucs = self.edges[e1]
72 | if e2 in lsucs:
73 | lsucs.remove(e2)
74 |
75 | lpreds = self.reverse_edges[e2]
76 | if e1 in lpreds:
77 | lpreds.remove(e1)
78 |
79 | def add_catch_edge(self, e1, e2):
80 | lsucs = self.catch_edges[e1]
81 | if e2 not in lsucs:
82 | lsucs.append(e2)
83 | lpreds = self.reverse_catch_edges[e2]
84 | if e1 not in lpreds:
85 | lpreds.append(e1)
86 |
87 | def remove_node(self, node):
88 | preds = self.reverse_edges.get(node, [])
89 | for pred in preds:
90 | self.edges[pred].remove(node)
91 |
92 | succs = self.edges.get(node, [])
93 | for suc in succs:
94 | self.reverse_edges[suc].remove(node)
95 |
96 | exc_preds = self.reverse_catch_edges.pop(node, [])
97 | for pred in exc_preds:
98 | self.catch_edges[pred].remove(node)
99 |
100 | exc_succs = self.catch_edges.pop(node, [])
101 | for suc in exc_succs:
102 | self.reverse_catch_edges[suc].remove(node)
103 |
104 | self.nodes.remove(node)
105 | if node in self.rpo:
106 | self.rpo.remove(node)
107 | del node
108 |
109 | def number_ins(self):
110 | self.loc_to_ins = {}
111 | self.loc_to_node = {}
112 | num = 0
113 | for node in self.rpo:
114 | start_node = num
115 | num = node.number_ins(num)
116 | end_node = num - 1
117 | self.loc_to_ins.update(node.get_loc_with_ins())
118 | self.loc_to_node[start_node, end_node] = node
119 |
120 | def get_ins_from_loc(self, loc):
121 | return self.loc_to_ins.get(loc)
122 |
123 | def get_node_from_loc(self, loc):
124 | for (start, end), node in self.loc_to_node.items():
125 | if start <= loc <= end:
126 | return node
127 |
128 | def remove_ins(self, loc):
129 | ins = self.get_ins_from_loc(loc)
130 | self.get_node_from_loc(loc).remove_ins(loc, ins)
131 | self.loc_to_ins.pop(loc)
132 |
133 | def compute_rpo(self):
134 | """
135 | Number the nodes in reverse post order.
136 | An RPO traversal visit as many predecessors of a node as possible
137 | before visiting the node itself.
138 | """
139 | nb = len(self.nodes) + 1
140 | for node in self.post_order():
141 | node.num = nb - node.po
142 | self.rpo = sorted(self.nodes, key=lambda n: n.num)
143 |
144 | def compute_block_order(self):
145 | list = sorted(self.nodes, key=lambda n: n.start)
146 | for num, node in enumerate(list):
147 | node.num = num
148 | return list
149 |
150 | def post_order(self):
151 | """
152 | Return the nodes of the graph in post-order i.e we visit all the
153 | children of a node before visiting the node itself.
154 | """
155 |
156 | def _visit(n, cnt):
157 | visited.add(n)
158 | for suc in self.all_sucs(n):
159 | if suc not in visited:
160 | for cnt, s in _visit(suc, cnt):
161 | yield cnt, s
162 | n.po = cnt
163 | yield cnt + 1, n
164 |
165 | visited = set()
166 | for _, node in _visit(self.entry, 1):
167 | yield node
168 |
169 | def immediate_dominators(self):
170 | return dom_lt(self)
171 |
172 | def __len__(self):
173 | return len(self.nodes)
174 |
175 | def __repr__(self):
176 | return str(self.nodes)
177 |
178 | def __iter__(self):
179 | for node in self.nodes:
180 | yield node
181 |
182 |
183 | def dom_lt(graph):
184 | """Dominator algorithm from Lengaeur-Tarjan"""
185 |
186 | def _dfs(v, n):
187 | semi[v] = n = n + 1
188 | vertex[n] = label[v] = v
189 | ancestor[v] = 0
190 | for w in graph.all_sucs(v):
191 | if not semi[w]:
192 | parent[w] = v
193 | n = _dfs(w, n)
194 | pred[w].add(v)
195 | return n
196 |
197 | def _compress(v):
198 | u = ancestor[v]
199 | if ancestor[u]:
200 | _compress(u)
201 | if semi[label[u]] < semi[label[v]]:
202 | label[v] = label[u]
203 | ancestor[v] = ancestor[u]
204 |
205 | def _eval(v):
206 | if ancestor[v]:
207 | _compress(v)
208 | return label[v]
209 | return v
210 |
211 | def _link(v, w):
212 | ancestor[w] = v
213 |
214 | parent, ancestor, vertex = {}, {}, {}
215 | label, dom = {}, {}
216 | pred, bucket = defaultdict(set), defaultdict(set)
217 |
218 | # Step 1:
219 | semi = {v: 0 for v in graph.nodes}
220 | n = _dfs(graph.entry, 0)
221 | for i in range(n, 1, -1):
222 | w = vertex[i]
223 | # Step 2:
224 | for v in pred[w]:
225 | u = _eval(v)
226 | y = semi[w] = min(semi[w], semi[u])
227 | bucket[vertex[y]].add(w)
228 | pw = parent[w]
229 | _link(pw, w)
230 | # Step 3:
231 | bpw = bucket[pw]
232 | while bpw:
233 | v = bpw.pop()
234 | u = _eval(v)
235 | dom[v] = u if semi[u] < semi[v] else pw
236 | # Step 4:
237 | for i in range(2, n + 1):
238 | w = vertex[i]
239 | dw = dom[w]
240 | if dw != vertex[semi[w]]:
241 | dom[w] = dom[dw]
242 | dom[graph.entry] = None
243 | return dom
244 |
245 |
246 | def bfs(start):
247 | to_visit = [start]
248 | visited = set([start])
249 | while to_visit:
250 | node = to_visit.pop(0)
251 | yield node
252 | if node.exception_analysis:
253 | for _, _, exception in node.exception_analysis.exceptions:
254 | if exception not in visited:
255 | to_visit.append(exception)
256 | visited.add(exception)
257 | for _, _, child in node.childs:
258 | if child not in visited:
259 | to_visit.append(child)
260 | visited.add(child)
261 |
262 |
263 | def construct(start_block):
264 | bfs_blocks = bfs(start_block)
265 |
266 | graph = Graph()
267 |
268 | block_to_node = {}
269 | node_to_landing_pad = {}
270 |
271 | # 每个异常exception_analysis 对应一个分发异常的landingping_pad, 不同的block可以有相同的异常处理
272 | exception_to_landing_pad = {}
273 |
274 | for block in bfs_blocks:
275 | node = block_to_node.get(block)
276 | if node is None:
277 | node = IrBasicBlock(block)
278 | block_to_node[block] = node
279 | graph.add_node(node)
280 |
281 | if block.exception_analysis:
282 | if block.exception_analysis in exception_to_landing_pad:
283 | landing_pad = exception_to_landing_pad[block.exception_analysis]
284 | else:
285 | # 初始化 LandingPad
286 | landing_pad = LandingPad(node)
287 | graph.add_landing_pad(landing_pad)
288 | exception_to_landing_pad[block.exception_analysis] = landing_pad
289 | for _type, _, exception_target in block.exception_analysis.exceptions:
290 | catch_node = block_to_node.get(exception_target)
291 | if catch_node is None:
292 | catch_node = IrBasicBlock(exception_target)
293 | block_to_node[exception_target] = catch_node
294 |
295 | catch_node.set_catch_type(_type)
296 | catch_node.in_catch = True
297 |
298 | landing_pad.add_catch_handle(_type, catch_node)
299 |
300 | # 将catch 节点加入到node后继
301 | for _type, _, exception_target in block.exception_analysis.exceptions:
302 | catch_node = block_to_node.get(exception_target)
303 | assert catch_node is not None
304 | node.add_catch_successor(catch_node)
305 | graph.add_catch_edge(node, catch_node)
306 | # 更新节点对应的LandingPad
307 | node_to_landing_pad[node] = landing_pad
308 |
309 | for _, _, child_block in block.childs:
310 | child_node = block_to_node.get(child_block)
311 | if child_node is None:
312 | child_node = IrBasicBlock(child_block)
313 | block_to_node[child_block] = child_node
314 | graph.add_edge(node, child_node)
315 |
316 | graph.entry = block_to_node[start_block]
317 |
318 | graph.compute_rpo()
319 |
320 | offset_to_node = {}
321 | for node in graph.rpo:
322 | if node.start >= 0:
323 | offset_to_node[node.start] = node
324 |
325 | graph.node_to_landing_pad = node_to_landing_pad
326 | graph.offset_to_node = offset_to_node
327 | for node in graph.rpo:
328 | preds = [pred for pred in graph.all_preds(node) if pred.num < node.num]
329 | if preds and all(pred.in_catch for pred in preds):
330 | node.in_catch = True
331 |
332 | return graph
333 |
334 |
335 |
--------------------------------------------------------------------------------
/dex2c/instruction.py:
--------------------------------------------------------------------------------
1 | # encoding=utf8
2 | #
3 | # Copyright (C) 2012, Geoffroy Gueguen
4 | # All rights reserved.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS-IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | import logging
19 | from builtins import object
20 | from typing import List, Set
21 | from dex2c import util
22 |
23 | logger = logging.getLogger('dex2c.instruction')
24 |
25 |
26 | class Value(object):
27 | def __init__(self):
28 | self.var_type = None
29 | self.type_sealed = False
30 |
31 | self.definition = None
32 | self.uses = set()
33 | self.is_const = False
34 |
35 | def set_type(self, vtype: str):
36 | if vtype is None or self.type_sealed:
37 | return False
38 |
39 | self.type_sealed = True
40 | if self.var_type is None:
41 | self.var_type = vtype
42 | return True
43 |
44 | if self.var_type == vtype:
45 | return False
46 | else:
47 | self.var_type = vtype
48 | return True
49 |
50 | def refine_type(self, vtype: str):
51 |
52 | if vtype is None or self.type_sealed or self.var_type == vtype:
53 | return False
54 |
55 | if self.var_type is None:
56 | self.var_type = vtype
57 | return True
58 |
59 | if util.is_java_lang_object(vtype) and util.is_ref(self.var_type):
60 | return False
61 |
62 | if util.is_java_lang_object(self.var_type) and util.is_ref(vtype):
63 | return False
64 |
65 | if (util.is_int(self.var_type) and util.is_int(vtype)) or \
66 | (util.is_float(self.var_type) and util.is_float(vtype)):
67 | new_type = util.get_smaller_type(self.var_type, vtype)
68 | if new_type != self.var_type:
69 | self.var_type = new_type
70 | return True
71 | else:
72 | return False
73 | elif util.is_int(self.var_type) and (util.is_float(vtype) or util.is_ref(vtype)):
74 | # 常量转换成浮点,提升为浮点类型,或者引用类型 0->NULL, 0->int_to_float()
75 | if self.is_const:
76 | # 常量转换成浮点,需要调用相应的帮助函数
77 | self.var_type = vtype
78 | return True
79 | else:
80 | if util.is_float(vtype):
81 | # 可以无损转化成浮点类型
82 | return False
83 | else:
84 | raise Exception("unable to refine type %s %s" % (self.var_type, vtype))
85 | else:
86 | new_type = util.merge_type(self.var_type, vtype)
87 | if new_type is None:
88 | raise Exception("unable to refine type %s %s" % (self.var_type, vtype))
89 | if self.var_type != new_type:
90 | self.var_type = new_type
91 | return True
92 | else:
93 | return False
94 |
95 | def get_type(self):
96 | return self.var_type
97 |
98 | def use_empty(self):
99 | return len(self.uses) == 0
100 |
101 | def get_uses(self):
102 | return self.uses
103 |
104 | def get_users(self):
105 | users = set()
106 | for use in self.uses:
107 | users.add(use.get_user())
108 | return list(users)
109 |
110 | def add_user(self, instr):
111 | for use in self.uses:
112 | if use.get_user() == instr:
113 | return
114 | else:
115 | use = Use(self, instr)
116 | self.uses.add(use)
117 |
118 | def visit_decl(self, visitor):
119 | return visitor.visit_decl(self)
120 |
121 | def remove_user(self, user):
122 | new_uses = set()
123 | for use in self.uses:
124 | if user != use.get_user():
125 | new_uses.add(use)
126 | self.uses = new_uses
127 |
128 | def replace_all_uses_with(self, new_value):
129 | for use in self.uses:
130 | user = use.get_user()
131 | user.replase_use_of_with(use.get_value(), new_value)
132 | self.uses.clear()
133 |
134 |
135 | class Use(object):
136 | def __init__(self, value: Value, user):
137 | self.value = value
138 | self.user = user
139 |
140 | def get_user(self):
141 | return self.user
142 |
143 | def get_value(self):
144 | return self.value
145 |
146 |
147 | class Constant(Value):
148 | def __init__(self, value, vtype=None):
149 | super(Constant, self).__init__()
150 | self.constant = value
151 | self.is_const = True
152 | if vtype:
153 | self.refine_type(vtype)
154 |
155 | def get_constant(self):
156 | if self.var_type and self.var_type[0] == 'L':
157 | return util.hex_escape_string(self.constant)
158 | else:
159 | return self.constant
160 |
161 | def visit(self, visitor):
162 | return visitor.visit_constant(self)
163 |
164 | def visit_decl(self, visitor):
165 | return visitor.visit_decl(self)
166 |
167 | def __str__(self):
168 | atype = self.var_type
169 | if atype == 'F':
170 | return 'd2c_bitcast_to_float(%r)' % self.constant
171 | elif atype == 'D':
172 | return 'd2c_bitcast_to_double(%r)' % self.constant
173 | elif util.is_int(atype) or util.is_long(atype):
174 | return '%r' % self.constant
175 | else:
176 | return '%s' % (self.get_constant())
177 |
178 |
179 | class Variable(Value):
180 | def __init__(self, register, version):
181 | super(Variable, self).__init__()
182 | self.register = register
183 | self.version = version
184 |
185 | def set_type(self, vtype: str):
186 | return super(Variable, self).set_type(vtype)
187 |
188 | def refine_type(self, vtype: str):
189 | return super(Variable, self).refine_type(vtype)
190 |
191 | def get_register(self):
192 | return self.register
193 |
194 | def visit(self, visitor):
195 | return visitor.visit_variable(self)
196 |
197 | def visit_decl(self, visitor):
198 | return visitor.visit_decl(self)
199 |
200 | def __str__(self):
201 | return 'v%s_%s' % (self.register if self.register >= 0 else 'Result', self.version)
202 |
203 |
204 | class Phi(Variable):
205 | def __init__(self, register, version):
206 | super(Phi, self).__init__(register, version)
207 | self.operands = {}
208 | self.block = None
209 | self.phi_users = set()
210 |
211 | def get_operands(self):
212 | return self.operands
213 |
214 | def set_block(self, block):
215 | self.block = block
216 |
217 | def get_block(self):
218 | return self.block
219 |
220 | def add_operand(self, pred, value):
221 | self.operands[pred] = value
222 | value.add_user(self)
223 |
224 | def get_incoming_blocks(self, value):
225 | result = []
226 | for k, v in self.operands.items():
227 | if v == value:
228 | result.append(k)
229 | return result
230 |
231 | def remove_operand(self, pred):
232 | self.operands.pop(pred)
233 |
234 | def replase_use_of_with(self, old: Value, new: Value):
235 | for pred, value in self.operands.items():
236 | if value == old:
237 | value.remove_user(self)
238 | new.add_user(self)
239 | self.operands[pred] = new
240 |
241 | def resolve_type(self):
242 | same_op_type = None
243 |
244 | for op in self.operands.values():
245 | if isinstance(op, Constant):
246 | continue
247 | op_type = op.get_type()
248 | if same_op_type and op_type != same_op_type:
249 | op_type = util.merge_type(same_op_type, op_type)
250 | same_op_type = op_type
251 |
252 | if same_op_type:
253 | new_type = same_op_type
254 | else:
255 | new_type = self.var_type
256 |
257 | Changed = False
258 | if new_type:
259 | if self.var_type != new_type:
260 | Changed |= self.refine_type(new_type)
261 | for op in self.operands.values():
262 | if isinstance(op, Constant):
263 | continue
264 | if op.get_type() != new_type:
265 | Changed |= op.refine_type(new_type)
266 | return Changed
267 |
268 | def remove_trivial_phi(self):
269 | # return
270 | same = None
271 | for op in self.operands.values():
272 | if op == same or op == self:
273 | continue
274 |
275 | if not same is None:
276 | return False
277 | same = op
278 |
279 | for op in self.operands.values():
280 | op.remove_user(self)
281 |
282 | self.replace_all_uses_with(same)
283 | self.block.remove_phi(self)
284 | assert len(self.uses) == 0
285 | return True
286 |
287 | def print(self):
288 | s = 'v%s_%s = Phi(' % (self.register, self.version)
289 | vars = []
290 | for n, v in self.operands.items():
291 | vars.append(str(v))
292 | s += ','.join(vars)
293 | s += ')'
294 | return s
295 |
296 |
297 | class Instruction(object):
298 | def __init__(self):
299 | self.value: Value = None
300 | self.operands: List[Value] = []
301 | self.parent = None # bb
302 | self.offset = -1 # current instruction's offset, used by branch instruction
303 | self.next_offset = -1 # next instruction's offset, used to get next basicblock
304 | self.dvm_instr = None
305 |
306 | # 活跃信息,如果一个引用类型变量在live_in但不在live_out,需要释放引用
307 | self.live_in: Set[Value] = set()
308 | self.live_out: Set[Value] = set()
309 |
310 | def set_value(self, value):
311 | self.value = value
312 |
313 | def set_value_type(self, vtype):
314 | return self.value.set_type(vtype)
315 |
316 | def get_value_type(self):
317 | return self.value.get_type()
318 |
319 | def set_operand_type(self, index, vtype):
320 | self.operands[index].refine_type(vtype)
321 |
322 | def get_operand_type(self, index):
323 | self.operands[index].get_type()
324 |
325 | def get_operans_number(self):
326 | return len(self.operands)
327 |
328 | def resolve_type(self):
329 | return False
330 |
331 | def is_const(self):
332 | return False
333 |
334 | def get_value(self):
335 | return self.value
336 |
337 | def get_users(self):
338 | return list(self.value.get_users())
339 |
340 | def add_user(self, instr):
341 | self.value.add_user(instr)
342 |
343 | def remove_user(self, user):
344 | self.value.remove_user(user)
345 |
346 | def replase_use_of_with(self, old_var: Value, new_var: Value):
347 | for idx, operand in enumerate(self.operands):
348 | if old_var == operand:
349 | self.operands[idx] = new_var
350 | new_var.add_user(self)
351 | old_var.remove_user(self)
352 |
353 | def visit(self, visitor):
354 | pass
355 |
356 | def get_class(self):
357 | return None
358 |
359 | def get_field(self):
360 | return None
361 |
362 | def get_call_method(self):
363 | return None
364 |
365 | def dump(self):
366 | if self.dvm_instr is not None:
367 | return '%x:%s %s' % (
368 | self.offset, self.dvm_instr.get_name(), util.hex_escape_string(self.dvm_instr.get_output()))
369 | else:
370 | return ''
371 |
372 |
373 | class LoadConstant(Instruction):
374 | def __init__(self, value, cst, obfus=False):
375 | super(LoadConstant, self).__init__()
376 | self.value = value
377 | self.value.refine_type(cst.get_type())
378 | self.value.is_const = True
379 | self.operands.append(cst)
380 | self.obfus = obfus
381 |
382 | @property
383 | def constant(self):
384 | return self.operands[0]
385 |
386 | def get_cst(self):
387 | return self.operands[0]
388 |
389 | def get_class(self):
390 | cst_type = self.get_cst().get_type()
391 | if cst_type == 'Ljava/lang/Class;':
392 | return self.get_cst().get_constant()
393 | else:
394 | return None
395 |
396 | def resolve_type(self):
397 | return False
398 |
399 | def visit(self, visitor):
400 | return visitor.visit_load_constant(self, self.obfus)
401 |
402 | def __str__(self):
403 | return '%s = %s' % (str(self.value), str(self.operands[0]))
404 |
405 |
406 | class Param(object):
407 | def __init__(self, value):
408 | self.declared = True
409 | self.value = value
410 | self.this = False
411 |
412 | def get_value(self):
413 | return self.value
414 |
415 | def visit(self, visitor):
416 | return visitor.visit_param(self.value)
417 |
418 | def __str__(self):
419 | return 'PARAM_%s' % self.name
420 |
421 |
422 | class ThisParam(Param):
423 | def __init__(self, value):
424 | super(ThisParam, self).__init__(value)
425 | self.this = True
426 |
427 | def visit(self, visitor):
428 | return visitor.visit_this()
429 |
430 | def __str__(self):
431 | return 'THIS'
432 |
433 |
434 | class MoveParam(Instruction):
435 | def __init__(self, param):
436 | super(MoveParam, self).__init__()
437 | self.param = param
438 |
439 | def visit(self, visitor):
440 | return visitor.visit_move_param(self)
441 |
442 | def get_value(self):
443 | return self.param.get_value()
444 |
445 | def get_param(self):
446 | return self.param
447 |
448 | def __str__(self):
449 | return 'MoveParam(%s)' % self.param.get_value()
450 |
451 |
452 | class MoveExpression(Instruction):
453 | def __init__(self, lhs, rhs):
454 | super(MoveExpression, self).__init__()
455 | self.value = lhs
456 | self.operands.append(rhs)
457 | rhs.add_user(self)
458 |
459 | def visit(self, visitor):
460 | return visitor.visit_move(self.value, self.operands[0])
461 |
462 | def resolve_type(self):
463 | op_type = self.operands[0].get_type()
464 | value_type = self.value.get_type()
465 |
466 | new_type = util.merge_type(op_type, value_type)
467 | if new_type is None:
468 | return False
469 |
470 | Changed = False
471 | if self.operands[0].type_sealed:
472 | Changed |= self.set_value_type(new_type)
473 | else:
474 | Changed |= self.value.refine_type(new_type)
475 | Changed |= self.operands[0].refine_type(new_type)
476 |
477 | return Changed
478 |
479 | def __str__(self):
480 | return '%s = %s' % (self.value, self.operands[0])
481 |
482 |
483 | class MoveResultExpression(MoveExpression):
484 | def __init__(self, lhs, rhs):
485 | super(MoveResultExpression, self).__init__(lhs, rhs)
486 |
487 | def visit(self, visitor):
488 | return visitor.visit_move_result(self, self.value, self.operands[0])
489 |
490 | def __str__(self):
491 | return '%s = %s' % (self.value, self.operands[0])
492 |
493 |
494 | class ArrayStoreInstruction(Instruction):
495 | def __init__(self, rhs, array, index, _type):
496 | super(ArrayStoreInstruction, self).__init__()
497 | rhs.add_user(self)
498 | array.add_user(self)
499 | index.add_user(self)
500 | self.operands.append(rhs)
501 | self.operands.append(array)
502 | self.operands.append(index)
503 | self.elem_type = _type
504 |
505 | @property
506 | def array(self):
507 | return self.operands[1]
508 |
509 | @property
510 | def index(self):
511 | return self.operands[2]
512 |
513 | def resolve_type(self):
514 | elem_type = self.get_elem_type()
515 | Changed = self.index.set_type('I')
516 | if elem_type:
517 | Changed |= self.operands[0].refine_type(elem_type)
518 | Changed |= self.array.refine_type('[' + elem_type)
519 | return Changed
520 |
521 | def get_elem_type(self):
522 | if self.elem_type:
523 | return self.elem_type
524 | else:
525 | if util.is_array(self.array.get_type()):
526 | type1 = self.array.get_type()[1:]
527 | else:
528 | type1 = None
529 | type2 = self.operands[0].get_type()
530 | return util.merge_type(type1, type2)
531 |
532 | def visit(self, visitor):
533 | return visitor.visit_astore(self, self.array,
534 | self.index,
535 | self.operands[0])
536 |
537 | def __str__(self):
538 | return '%s[%s] = %s' % (self.array, self.index, self.operands[0])
539 |
540 |
541 | class StaticInstruction(Instruction):
542 | def __init__(self, rhs, klass, ftype, name):
543 | super(StaticInstruction, self).__init__()
544 | self.cls = util.get_type(klass)
545 | self.ftype = ftype
546 | self.name = name
547 | self.clsdesc = klass
548 | rhs.add_user(self)
549 | self.operands.append(rhs)
550 |
551 | def get_class(self):
552 | return self.clsdesc
553 |
554 | def get_field(self):
555 | return '%s.%s' % (self.clsdesc, self.name)
556 |
557 | def resolve_type(self):
558 | return self.operands[0].refine_type(self.ftype)
559 |
560 | def visit(self, visitor):
561 | return visitor.visit_put_static(self, self.clsdesc, self.name, self.ftype, self.operands[0])
562 |
563 | def __str__(self):
564 | return '%s.%s = %s' % (self.cls, self.name, self.operands[0])
565 |
566 |
567 | class InstanceInstruction(Instruction):
568 | def __init__(self, rhs, lhs, klass, atype, name):
569 | super(InstanceInstruction, self).__init__()
570 | self.atype = atype
571 | self.cls = util.get_type(klass)
572 | self.name = name
573 | self.clsdesc = klass
574 |
575 | lhs.add_user(self)
576 | rhs.add_user(self)
577 | self.operands.append(lhs)
578 | self.operands.append(rhs)
579 |
580 | def get_class(self):
581 | return self.clsdesc
582 |
583 | def get_field(self):
584 | return '%s.%s' % (self.clsdesc, self.name)
585 |
586 | def resolve_type(self):
587 | Changed = False
588 | Changed |= self.operands[0].refine_type(self.clsdesc)
589 | Changed |= self.operands[1].refine_type(self.atype)
590 | return Changed
591 |
592 | def visit(self, visitor):
593 | return visitor.visit_put_instance(self, self.operands[0], self.operands[1], self.atype, self.clsdesc, self.name)
594 |
595 | def __str__(self):
596 | return '%s.%s = %s' % (self.operands[0], self.name, self.operands[1])
597 |
598 |
599 | class NewInstance(Instruction):
600 | def __init__(self, lhs, ins_type):
601 | super(NewInstance, self).__init__()
602 | self.value = lhs
603 | self.value.refine_type(ins_type)
604 | self.type = ins_type
605 |
606 | def get_type(self):
607 | return self.type
608 |
609 | def get_class(self):
610 | return self.type
611 |
612 | def resolve_type(self):
613 | return self.set_value_type(self.type)
614 |
615 | def visit(self, visitor):
616 | return visitor.visit_new(self, self.value, self.type)
617 |
618 | def __str__(self):
619 | return '%s = NEW(%s)' % (self.value, self.type)
620 |
621 |
622 | class InvokeInstruction(Instruction):
623 | def __init__(self, invoke_type, clsname, name, thiz, result, rtype, ptype, args, triple):
624 | super(InvokeInstruction, self).__init__()
625 | self.invoke_type = invoke_type
626 | self.is_static = True if invoke_type == 'static' else False
627 | self.clsdesc = clsname
628 | self.value = result
629 | self.name = name
630 |
631 | if not self.is_static:
632 | self.operands.append(thiz)
633 | thiz.add_user(self)
634 |
635 | if result:
636 | result.refine_type(rtype)
637 |
638 | self.rtype = rtype
639 | self.ptype = ptype
640 | self.args = []
641 | for arg in args:
642 | arg.add_user(self)
643 | self.operands.append(arg)
644 |
645 | self.triple = triple
646 | assert (triple[1] == name)
647 |
648 | @property
649 | def thiz(self):
650 | if self.is_static:
651 | return None
652 | else:
653 | return self.operands[0]
654 |
655 | def get_class(self):
656 | return self.clsdesc
657 |
658 | def get_call_method(self):
659 | return '%s->%s(%s)' % (self.clsdesc, self.name, ''.join(self.ptype))
660 |
661 | def resolve_type(self):
662 | Changed = False
663 | if self.is_static:
664 | assert self.thiz is None
665 | args = self.operands
666 | else:
667 | args = self.operands[1:]
668 |
669 | if self.thiz and self.thiz.get_type() != self.clsdesc:
670 | Changed |= self.thiz.refine_type(self.clsdesc)
671 |
672 | for idx, arg in enumerate(args):
673 | Changed |= arg.refine_type(self.ptype[idx])
674 |
675 | if self.value:
676 | Changed |= self.set_value_type(self.rtype)
677 | return Changed
678 |
679 | def visit(self, visitor):
680 | if self.is_static:
681 | assert self.thiz is None
682 | args = self.operands
683 | else:
684 | args = self.operands[1:]
685 | return visitor.visit_invoke(self, self.invoke_type, self.name, self.thiz, self.ptype,
686 | self.rtype, args, self.clsdesc)
687 |
688 | def __str__(self):
689 | args = []
690 | if not self.is_static:
691 | args.append(self.thiz)
692 | args.extend(self.args)
693 | return '%s.%s(%s)' % (self.clsdesc, self.name,
694 | ', '.join('%s' % i for i in args))
695 |
696 |
697 | class InvokeRangeInstruction(InvokeInstruction):
698 | def __init__(self, clsname, name, rtype, ptype, args, triple):
699 | base = args.pop(0)
700 | super(InvokeRangeInstruction, self).__init__(clsname, name, base, rtype,
701 | ptype, args, triple)
702 |
703 |
704 | class InvokeDirectInstruction(InvokeInstruction):
705 | def __init__(self, clsname, name, base, rtype, ptype, args, triple):
706 | super(InvokeDirectInstruction, self).__init__(
707 | clsname, name, base, rtype, ptype, args, triple)
708 |
709 |
710 | class InvokeStaticInstruction(InvokeInstruction):
711 | def __init__(self, clsname, name, base, rtype, ptype, args, triple):
712 | super(InvokeStaticInstruction, self).__init__(
713 | clsname, name, base, rtype, ptype, args, triple)
714 |
715 |
716 | class InvokeSuperInstruction(InvokeInstruction):
717 | def __init__(self, clsname, name, base, rtype, ptype, args, triple):
718 | super(InvokeSuperInstruction, self).__init__(clsname, name, base, rtype,
719 | ptype, args, triple)
720 |
721 |
722 | class ReturnInstruction(Instruction):
723 | def __init__(self, arg, rtype=None):
724 | super(ReturnInstruction, self).__init__()
725 | self.rtype = rtype
726 | if arg:
727 | arg.add_user(self)
728 | self.operands.append(arg)
729 |
730 | @property
731 | def retval(self):
732 | if self.rtype:
733 | return self.operands[0]
734 | else:
735 | return None
736 |
737 | def visit(self, visitor):
738 | if self.rtype is None:
739 | return visitor.visit_return_void()
740 | else:
741 | return visitor.visit_return(self.retval)
742 |
743 | def resolve_type(self):
744 | if self.rtype:
745 | return self.retval.refine_type(self.rtype)
746 | else:
747 | return False
748 |
749 | def __str__(self):
750 | if self.retval is not None:
751 | return 'RETURN(%s)' % self.retval
752 | else:
753 | return 'RETURN'
754 |
755 |
756 | class NopExpression(Instruction):
757 | def __init__(self):
758 | super(NopExpression, self).__init__()
759 | pass
760 |
761 | def visit(self, visitor):
762 | return visitor.visit_nop()
763 |
764 |
765 | class GotoInst(Instruction):
766 | def __init__(self, target):
767 | super(GotoInst, self).__init__()
768 | self.target = target
769 |
770 | def visit(self, visitor):
771 | return visitor.visit_goto((self.offset // 2 + self.target) * 2)
772 |
773 | def __str__(self):
774 | return "GOTO(%x)" % (self.target)
775 |
776 |
777 | class SwitchExpression(Instruction):
778 | def __init__(self, src, cases):
779 | super(SwitchExpression, self).__init__()
780 | # src.set_type('I')
781 | src.add_user(self)
782 | self.cases = cases
783 | self.operands.append(src)
784 |
785 | def visit(self, visitor):
786 | return visitor.visit_switch_node(self, self.operands[0], self.cases)
787 |
788 | def resolve_type(self):
789 | return self.operands[0].refine_type('I')
790 |
791 | def __str__(self):
792 | return 'SWITCH(%s)' % (self.operands[0])
793 |
794 |
795 | class CheckCastExpression(Instruction):
796 | def __init__(self, arg, _type, descriptor=None):
797 | super(CheckCastExpression, self).__init__()
798 | self.type = descriptor
799 | self.clsdesc = descriptor
800 | arg.add_user(self)
801 | self.operands.append(arg)
802 |
803 | def get_type(self):
804 | return self.type
805 |
806 | def get_class(self):
807 | return self.clsdesc
808 |
809 | def resolve_type(self):
810 | return self.operands[0].refine_type(self.type)
811 |
812 | def visit(self, visitor):
813 | return visitor.visit_check_cast(self, self.operands[0], self.clsdesc)
814 |
815 | def __str__(self):
816 | return 'CAST(%s) %s' % (self.type, self.operands[0])
817 |
818 |
819 | class InstanceOfExpression(Instruction):
820 | def __init__(self, result, obj, clsdesc):
821 | super(InstanceOfExpression, self).__init__()
822 | self.clsdesc = clsdesc
823 | self.value = result
824 | obj.add_user(self)
825 | self.operands.append(obj)
826 |
827 | def get_class(self):
828 | return self.clsdesc
829 |
830 | def resolve_type(self):
831 | Changed = self.operands[0].refine_type(self.clsdesc)
832 | Changed |= self.set_value_type('Z')
833 | return Changed
834 |
835 | def visit(self, visitor):
836 | return visitor.visit_instanceof(self, self.value, self.operands[0], self.clsdesc)
837 |
838 | def __str__(self):
839 | return '(%s instanceof %s)' % (self.value, self.clsdesc)
840 |
841 |
842 | class ArrayExpression(Instruction):
843 | def __init__(self):
844 | super(ArrayExpression, self).__init__()
845 |
846 |
847 | class ArrayLoadExpression(ArrayExpression):
848 | def __init__(self, result, arg, index, _type):
849 | super(ArrayLoadExpression, self).__init__()
850 | self.value = result
851 | arg.add_user(self)
852 | index.add_user(self)
853 | self.operands.append(arg)
854 | self.operands.append(index)
855 | self.elem_type = _type
856 |
857 | @property
858 | def array(self):
859 | return self.operands[0]
860 |
861 | @property
862 | def idx(self):
863 | return self.operands[1]
864 |
865 | def resolve_type(self):
866 | Changed = False
867 | elem_type = self.get_elem_type()
868 | if elem_type:
869 | Changed |= self.value.refine_type(elem_type)
870 | Changed |= self.array.refine_type('[' + elem_type)
871 | Changed |= self.idx.refine_type("I")
872 | return Changed
873 |
874 | def visit(self, visitor):
875 | return visitor.visit_aload(self, self.value, self.array, self.idx)
876 |
877 | def get_elem_type(self):
878 | if self.elem_type:
879 | return self.elem_type
880 | else:
881 | if util.is_array(self.array.get_type()):
882 | type1 = self.array.get_type()[1:]
883 | else:
884 | type1 = None
885 | type2 = self.get_value_type()
886 | return util.merge_type(type1, type2)
887 |
888 | def __str__(self):
889 | return '%s = ARRAYLOAD(%s, %s)' % (self.value, self.array, self.idx)
890 |
891 |
892 | class ArrayLengthExpression(ArrayExpression):
893 | def __init__(self, result, array):
894 | super(ArrayLengthExpression, self).__init__()
895 | self.value = result
896 | array.add_user(self)
897 | self.operands.append(array)
898 |
899 | @property
900 | def array(self):
901 | return self.operands[0]
902 |
903 | def resolve_type(self):
904 | return self.set_value_type('I')
905 |
906 | def visit(self, visitor):
907 | return visitor.visit_alength(self, self.value, self.array)
908 |
909 | def __str__(self):
910 | return 'ARRAYLEN(%s)' % self.array
911 |
912 |
913 | class NewArrayExpression(ArrayExpression):
914 | def __init__(self, result, asize, atype):
915 | super(NewArrayExpression, self).__init__()
916 | self.value = result
917 | asize.add_user(self)
918 | self.type = atype
919 | self.elem_type = atype[1:]
920 | self.operands.append(asize)
921 |
922 | def get_size(self):
923 | return self.operands[0]
924 |
925 | def get_elem_type(self):
926 | return self.elem_type
927 |
928 | def get_class(self):
929 | return self.elem_type
930 |
931 | def resolve_type(self):
932 | Changed = False
933 | Changed |= self.set_value_type(self.type)
934 | Changed |= self.operands[0].set_type('I')
935 | return Changed
936 |
937 | def visit(self, visitor):
938 | return visitor.visit_new_array(self, self.value, self.type, self.get_size())
939 |
940 | def __str__(self):
941 | return '%s = NEWARRAY_%s[%s]' % (self.value, self.type, self.get_size())
942 |
943 |
944 | class FilledArrayExpression(ArrayExpression):
945 | def __init__(self, result, asize, atype, args):
946 | super(FilledArrayExpression, self).__init__()
947 | self.value = result
948 | result.refine_type(atype)
949 | self.size = asize
950 | self.type = atype
951 | self.elem_type = atype[1:]
952 | for arg in args:
953 | arg.add_user(self)
954 | self.operands.append(arg)
955 |
956 | def get_class(self):
957 | return self.elem_type
958 |
959 | def resolve_type(self):
960 | Changed = False
961 | Changed |= self.set_value_type(self.type)
962 | for arg in self.operands:
963 | Changed |= arg.refine_type(self.elem_type)
964 | return Changed
965 |
966 | def visit(self, visitor):
967 | return visitor.visit_filled_new_array(self, self.value, self.type, self.size, self.operands)
968 |
969 |
970 | class FillArrayExpression(ArrayExpression):
971 | def __init__(self, reg, value):
972 | super(FillArrayExpression, self).__init__()
973 | self.filldata = value
974 | self.operands.append(reg)
975 | self.reg.add_user(self)
976 |
977 | @property
978 | def reg(self):
979 | return self.operands[0]
980 |
981 | def resolve_type(self):
982 | return False
983 |
984 | def visit(self, visitor):
985 | return visitor.visit_fill_array(self, self.reg, self.filldata)
986 |
987 |
988 | class MoveExceptionExpression(Instruction):
989 | def __init__(self, value, _type):
990 | super(MoveExceptionExpression, self).__init__()
991 | self.value = value
992 | self.value.refine_type(_type)
993 | self.type = _type
994 |
995 | def resolve_type(self):
996 | return self.value.refine_type(self.type)
997 |
998 | def visit(self, visitor):
999 | return visitor.visit_move_exception(self, self.value)
1000 |
1001 | def __str__(self):
1002 | return 'MOVE_EXCEPT %s(%s)' % (self.value, self.value.get_type())
1003 |
1004 |
1005 | class MonitorEnterExpression(Instruction):
1006 | def __init__(self, ref):
1007 | super(MonitorEnterExpression, self).__init__()
1008 | ref.add_user(self)
1009 | self.operands.append(ref)
1010 |
1011 | def resolve_type(self):
1012 | return self.operands[0].refine_type('Ljava/lang/Object;')
1013 |
1014 | def visit(self, visitor):
1015 | return visitor.visit_monitor_enter(self, self.operands[0])
1016 |
1017 | def __str__(self):
1018 | return 'MonitorEnter (%s)' % self.operands[0]
1019 |
1020 |
1021 | class MonitorExitExpression(Instruction):
1022 | def __init__(self, ref):
1023 | super(MonitorExitExpression, self).__init__()
1024 | ref.add_user(self)
1025 | self.operands.append(ref)
1026 |
1027 | def resolve_type(self):
1028 | return self.operands[0].refine_type('Ljava/lang/Object;')
1029 |
1030 | def visit(self, visitor):
1031 | return visitor.visit_monitor_exit(self, self.operands[0])
1032 |
1033 | def __str__(self):
1034 | return 'MonitorExit (%s)' % self.operands[0]
1035 |
1036 |
1037 | class ThrowExpression(Instruction):
1038 | def __init__(self, ref):
1039 | super(ThrowExpression, self).__init__()
1040 | ref.add_user(self)
1041 | self.operands.append(ref)
1042 |
1043 | def resolve_type(self):
1044 | return self.operands[0].set_type('Ljava/lang/Throwable;')
1045 |
1046 | def visit(self, visitor):
1047 | return visitor.visit_throw(self, self.operands[0])
1048 |
1049 | def __str__(self):
1050 | return 'Throw %s' % self.operands[0]
1051 |
1052 |
1053 | class BinaryExpression(Instruction):
1054 | def __init__(self, op, result, arg1, arg2, vtype):
1055 | super(BinaryExpression, self).__init__()
1056 | self.value = result
1057 | self.op = op
1058 |
1059 | self.operands.append(arg1)
1060 | self.operands.append(arg2)
1061 |
1062 | self.op_type = vtype
1063 |
1064 | arg1.add_user(self)
1065 | arg2.add_user(self)
1066 |
1067 | def resolve_type(self):
1068 | Changed = False
1069 | Changed |= self.value.refine_type(self.op_type)
1070 | for op in self.operands:
1071 | Changed |= op.refine_type(self.op_type)
1072 | return Changed
1073 |
1074 | def visit(self, visitor):
1075 | return visitor.visit_binary_expression(self, self.value, self.op, self.operands[0], self.operands[1])
1076 |
1077 | def __str__(self):
1078 | return '%s = %s %s %s' % (self.value, self.operands[0], self.op, self.operands[1])
1079 |
1080 |
1081 | class BinaryCompExpression(BinaryExpression):
1082 | def __init__(self, op, result, arg1, arg2, _type):
1083 | super(BinaryCompExpression, self).__init__(op, result, arg1, arg2, _type)
1084 | result.refine_type('I')
1085 |
1086 | def resolve_type(self):
1087 | Changed = False
1088 | Changed |= self.value.refine_type('I')
1089 | for op in self.operands:
1090 | Changed |= op.refine_type(self.op_type)
1091 | return Changed
1092 |
1093 |
1094 | class BinaryExpression2Addr(BinaryExpression):
1095 | def __init__(self, result, op, dest, arg, _type):
1096 | super(BinaryExpression2Addr, self).__init__(result, op, dest, arg, _type)
1097 |
1098 |
1099 | class BinaryExpressionLit(BinaryExpression):
1100 | def __init__(self, op, result, arg1, arg2):
1101 | super(BinaryExpressionLit, self).__init__(op, result, arg1, arg2, 'I')
1102 |
1103 |
1104 | class UnaryExpression(Instruction):
1105 | def __init__(self, result, op, arg, _type):
1106 | super(UnaryExpression, self).__init__()
1107 | result.refine_type(_type)
1108 | self.value = result
1109 | self.op = op
1110 | self.type = _type
1111 | self.operands.append(arg)
1112 | arg.add_user(self)
1113 |
1114 | def resolve_type(self):
1115 | return self.set_value_type(self.type)
1116 |
1117 | def visit(self, visitor):
1118 | return visitor.visit_unary_expression(self, self.value, self.op, self.operands[0])
1119 |
1120 | def __str__(self):
1121 | return '(%s, %s)' % (self.op, self.operands[0])
1122 |
1123 |
1124 | class CastExpression(Instruction):
1125 | def __init__(self, result, op, dest_type, arg, src_type):
1126 | super(CastExpression, self).__init__()
1127 | self.type = dest_type
1128 | self.src_type = src_type
1129 | self.op = op
1130 | self.value = result
1131 | self.value.refine_type(dest_type)
1132 | self.operands.append(arg)
1133 | arg.add_user(self)
1134 |
1135 | def get_type(self):
1136 | return self.type
1137 |
1138 | def resolve_type(self):
1139 | Changed = self.value.refine_type(self.type)
1140 | Changed |= self.operands[0].refine_type(self.src_type)
1141 | return Changed
1142 |
1143 | def visit(self, visitor):
1144 | return visitor.visit_cast(self.value, self.op, self.operands[0])
1145 |
1146 | def __str__(self):
1147 | return '%s = %s(%s)' % (self.value, self.op, self.operands[0])
1148 |
1149 |
1150 | CONDS = {'==': '!=', '!=': '==', '<': '>=', '<=': '>', '>=': '<', '>': '<=', }
1151 |
1152 |
1153 | class ConditionalExpression(Instruction):
1154 | def __init__(self, op, arg1, arg2, target):
1155 | super(ConditionalExpression, self).__init__()
1156 | self.op = op
1157 | self.target = target
1158 | arg1.add_user(self)
1159 | arg2.add_user(self)
1160 | self.operands.append(arg1)
1161 | self.operands.append(arg2)
1162 |
1163 | def get_target(self):
1164 | return self.target
1165 |
1166 | def resolve_type(self):
1167 | Changed = False
1168 | type1 = self.operands[0].get_type()
1169 | type2 = self.operands[1].get_type()
1170 |
1171 | # 引用类型可以比较
1172 | if (util.is_ref(type1) or util.is_array(type1)) and (util.is_ref(type2) or util.is_array(type2)):
1173 | return False
1174 |
1175 | new_type = util.merge_type(type1, type2)
1176 | Changed |= self.operands[0].refine_type(new_type)
1177 | Changed |= self.operands[1].refine_type(new_type)
1178 | return Changed
1179 |
1180 | def visit(self, visitor):
1181 | return visitor.visit_cond_expression(self, self.op, self.operands[0],
1182 | self.operands[1], (self.offset // 2 + self.target) * 2,
1183 | self.next_offset)
1184 |
1185 | def __str__(self):
1186 | return 'IF %s %s %s' % (self.operands[0], self.op, self.operands[1])
1187 |
1188 |
1189 | class ConditionalZExpression(Instruction):
1190 | def __init__(self, op, arg, target):
1191 | super(ConditionalZExpression, self).__init__()
1192 | self.op = op
1193 | self.target = target
1194 | arg.add_user(self)
1195 | self.operands.append(arg)
1196 |
1197 | # 无法使用该指令无法推断出操作类型
1198 | def resolve_type(self):
1199 | return False
1200 |
1201 | def visit(self, visitor):
1202 | return visitor.visit_condz_expression(self, self.op, self.operands[0], (self.offset // 2 + self.target) * 2,
1203 | self.next_offset)
1204 |
1205 | def __str__(self):
1206 | return 'IF %s %s 0' % (self.operands[0], self.op)
1207 |
1208 |
1209 | class InstanceExpression(Instruction):
1210 | def __init__(self, result, arg, klass, ftype, name):
1211 | super(InstanceExpression, self).__init__()
1212 | self.value = result
1213 | self.cls = util.get_type(klass)
1214 | self.ftype = ftype
1215 | self.name = name
1216 | self.clsdesc = klass
1217 |
1218 | arg.add_user(self)
1219 | self.operands.append(arg)
1220 |
1221 | def get_class(self):
1222 | return self.clsdesc
1223 |
1224 | def get_field(self):
1225 | return '%s.%s' % (self.clsdesc, self.name)
1226 |
1227 | def resolve_type(self):
1228 | Changed = self.set_value_type(self.ftype)
1229 | Changed |= self.operands[0].refine_type(self.clsdesc)
1230 | return Changed
1231 |
1232 | def get_type(self):
1233 | return self.ftype
1234 |
1235 | def visit(self, visitor):
1236 | return visitor.visit_get_instance(
1237 | self,
1238 | self.value,
1239 | self.operands[0],
1240 | self.ftype,
1241 | self.clsdesc,
1242 | self.name)
1243 |
1244 | def __str__(self):
1245 | return '%s = %s.%s' % (self.value, self.operands[0], self.name)
1246 |
1247 |
1248 | class StaticExpression(Instruction):
1249 | def __init__(self, result, cls_name, field_type, field_name):
1250 | super(StaticExpression, self).__init__()
1251 | self.value = result
1252 | self.cls = util.get_type(cls_name)
1253 | self.ftype = field_type
1254 | self.name = field_name
1255 | self.clsdesc = cls_name
1256 |
1257 | def get_class(self):
1258 | return self.clsdesc
1259 |
1260 | def get_field(self):
1261 | return '%s.%s' % (self.clsdesc, self.name)
1262 |
1263 | def resolve_type(self):
1264 | return self.set_value_type(self.ftype)
1265 |
1266 | def visit(self, visitor):
1267 | return visitor.visit_get_static(self, self.value, self.ftype, self.clsdesc, self.name)
1268 |
1269 | def __str__(self):
1270 | return '%s = %s.%s' % (self.value, self.cls, self.name)
1271 |
--------------------------------------------------------------------------------
/dex2c/util.py:
--------------------------------------------------------------------------------
1 | # encoding=utf8
2 | #
3 | # Copyright (c) 2012 Geoffroy Gueguen
4 | # All Rights Reserved.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS-IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | import logging
19 |
20 | logger = logging.getLogger('dex2c.util')
21 |
22 | TYPE_DESCRIPTOR = {
23 | 'V': 'Void',
24 | 'Z': 'Boolean',
25 | 'B': 'Byte',
26 | 'S': 'Short',
27 | 'C': 'Char',
28 | 'I': 'Int',
29 | 'J': 'Long',
30 | 'F': 'Float',
31 | 'D': 'Double',
32 | }
33 |
34 | DECL_JNI_TYPE = {
35 | 'Z': 'jboolean', # jboolean
36 | 'B': 'jbyte',
37 | 'S': 'jshort',
38 | 'C': 'jchar',
39 | 'I': 'jint',
40 | 'J': 'jlong',
41 | 'F': 'jfloat',
42 | 'D': 'jdouble',
43 | 'V': 'void',
44 | }
45 |
46 | PRIMITIVE_TYPE_ORDER = {
47 | 'Z': 1,
48 | 'B': 2,
49 | 'S': 3, # signed
50 | 'C': 3, # unsigned
51 | 'I': 5,
52 | 'J': 6,
53 | 'F': 8,
54 | 'D': 9,
55 | }
56 |
57 | ACCESS_FLAGS_CLASSES = {
58 | 0x1: 'public',
59 | 0x2: 'private',
60 | 0x4: 'protected',
61 | 0x8: 'static',
62 | 0x10: 'final',
63 | 0x200: 'interface',
64 | 0x400: 'abstract',
65 | 0x1000: 'synthetic',
66 | 0x2000: 'annotation',
67 | 0x4000: 'enum',
68 | }
69 |
70 | ACCESS_FLAGS_FIELDS = {
71 | 0x1: 'public',
72 | 0x2: 'private',
73 | 0x4: 'protected',
74 | 0x8: 'static',
75 | 0x10: 'final',
76 | 0x40: 'volatile',
77 | 0x80: 'transient',
78 | 0x1000: 'synthetic',
79 | 0x4000: 'enum',
80 | }
81 |
82 | ACCESS_FLAGS_METHODS = {
83 | 0x1: 'public',
84 | 0x2: 'private',
85 | 0x4: 'protected',
86 | 0x8: 'static',
87 | 0x10: 'final',
88 | 0x20: 'synchronized',
89 | 0x40: 'bridge',
90 | 0x80: 'varargs',
91 | 0x100: 'native',
92 | 0x400: 'abstract',
93 | 0x800: 'strictfp',
94 | 0x1000: 'synthetic',
95 | 0x10000: 'constructor',
96 | 0x20000: 'declared_synchronized',
97 | }
98 |
99 | ACCESS_ORDER = [0x1, 0x4, 0x2, 0x400, 0x8, 0x10, 0x80, 0x40, 0x20, 0x100, 0x800,
100 | 0x200, 0x1000, 0x2000, 0x4000, 0x10000, 0x20000]
101 |
102 | TYPE_LEN = {'J': 2, 'D': 2, }
103 |
104 |
105 | def get_access_class(access):
106 | sorted_access = [i for i in ACCESS_ORDER if i & access]
107 | return [ACCESS_FLAGS_CLASSES.get(flag, 'unkn_%d' % flag)
108 | for flag in sorted_access]
109 |
110 |
111 | def get_access_method(access):
112 | sorted_access = [i for i in ACCESS_ORDER if i & access]
113 | return [ACCESS_FLAGS_METHODS.get(flag, 'unkn_%d' % flag)
114 | for flag in sorted_access]
115 |
116 |
117 | def get_access_field(access):
118 | sorted_access = [i for i in ACCESS_ORDER if i & access]
119 | return [ACCESS_FLAGS_FIELDS.get(flag, 'unkn_%d' % flag)
120 | for flag in sorted_access]
121 |
122 |
123 | def build_path(graph, node1, node2, path=None):
124 | """
125 | Build the path from node1 to node2.
126 | The path is composed of all the nodes between node1 and node2,
127 | node1 excluded. Although if there is a loop starting from node1, it will be
128 | included in the path.
129 | """
130 | if path is None:
131 | path = []
132 | if node1 is node2:
133 | return path
134 | path.append(node2)
135 | for pred in graph.all_preds(node2):
136 | if pred in path:
137 | continue
138 | build_path(graph, node1, pred, path)
139 | return path
140 |
141 |
142 | def common_dom(idom, cur, pred):
143 | if not (cur and pred):
144 | return cur or pred
145 | while cur is not pred:
146 | while cur.num < pred.num:
147 | pred = idom[pred]
148 | while cur.num > pred.num:
149 | cur = idom[cur]
150 | return cur
151 |
152 |
153 | def merge_inner(clsdict):
154 | """
155 | Merge the inner class(es) of a class:
156 | e.g class A { ... } class A$foo{ ... } class A$bar{ ... }
157 | ==> class A { class foo{...} class bar{...} ... }
158 | """
159 | samelist = False
160 | done = {}
161 | while not samelist:
162 | samelist = True
163 | classlist = list(clsdict.keys())
164 | for classname in classlist:
165 | parts_name = classname.rsplit('$', 1)
166 | if len(parts_name) > 1:
167 | mainclass, innerclass = parts_name
168 | innerclass = innerclass[:-1] # remove ';' of the name
169 | mainclass += ';'
170 | if mainclass in clsdict:
171 | clsdict[mainclass].add_subclass(innerclass,
172 | clsdict[classname])
173 | clsdict[classname].name = innerclass
174 | done[classname] = clsdict[classname]
175 | del clsdict[classname]
176 | samelist = False
177 | elif mainclass in done:
178 | cls = done[mainclass]
179 | cls.add_subclass(innerclass, clsdict[classname])
180 | clsdict[classname].name = innerclass
181 | done[classname] = done[mainclass]
182 | del clsdict[classname]
183 | samelist = False
184 |
185 |
186 | def get_type_size(param):
187 | """
188 | Return the number of register needed by the type @param
189 | """
190 | return TYPE_LEN.get(param, 1)
191 |
192 |
193 | def get_type(atype, size=None):
194 | """
195 | Retrieve the java type of a descriptor (e.g : I)
196 | """
197 | res = TYPE_DESCRIPTOR.get(atype)
198 | if res is None:
199 | if atype[0] == 'L':
200 | res = atype[1:-1]
201 | elif atype[0] == '[':
202 | res = atype
203 | else:
204 | res = atype
205 | logger.debug('Unknown descriptor: "%s".', atype)
206 | return res
207 |
208 |
209 | def get_fully_qualified_class_name(signature):
210 | res = TYPE_DESCRIPTOR.get(signature)
211 | if res is None:
212 | if signature[0] == 'L':
213 | res = signature[1:-1]
214 | else:
215 | res = signature
216 | logger.debug('Unknown descriptor: "%s".', signature)
217 | return res
218 |
219 |
220 | def get_type_descriptor(atype):
221 | res = TYPE_DESCRIPTOR.get(atype)
222 | if res is None:
223 | res = 'Object'
224 | return res
225 |
226 |
227 | def is_primitive_type(atype):
228 | return atype and atype in PRIMITIVE_TYPE_ORDER
229 |
230 |
231 | def get_params_type(descriptor):
232 | """
233 | Return the parameters type of a descriptor (e.g (IC)V)
234 | """
235 | params = descriptor.split(')')[0][1:].split()
236 | if params:
237 | return [param for param in params]
238 | return []
239 |
240 |
241 | def get_method_triple(method, return_type=True):
242 | method_triple = method.get_triple()
243 | cls_name = method.class_name
244 | _, name, proto = method_triple
245 | if return_type:
246 | return cls_name, name, proto
247 | else:
248 | index = proto.find(')')
249 | proto = proto[:index + 1]
250 | return cls_name, name, proto
251 |
252 |
253 | def get_native_type(jtype):
254 | res = DECL_JNI_TYPE.get(jtype)
255 | if res is None:
256 | if jtype == 'Ljava/lang/String;':
257 | res = 'jstring'
258 | elif jtype[0] == 'L':
259 | res = 'jobject'
260 | elif jtype[0] == '[':
261 | res = 'jarray'
262 | else:
263 | res = 'jobject'
264 | logger.debug('Unknown descriptor: "%s".', jtype)
265 | return res
266 |
267 |
268 | def is_int(atype):
269 | return atype and atype in 'ZBCSIJ'
270 |
271 |
272 | def is_long(atype):
273 | return atype == 'J'
274 |
275 |
276 | def is_float(atype):
277 | return atype and atype in 'FD'
278 |
279 |
280 | def is_ref(atype):
281 | return atype and (atype[0] == 'L' or atype[0] == '[')
282 |
283 |
284 | def is_array(atype):
285 | return atype and atype[0] == '['
286 |
287 |
288 | def is_java_lang_object(atype):
289 | return atype and atype == 'Ljava/lang/Object;'
290 |
291 |
292 | def is_java_lang_object_array(atype):
293 | return is_array(atype) and atype.endswith('Ljava/lang/Object;')
294 |
295 |
296 | # Use for variable declaration
297 | def get_cdecl_type(atype):
298 | if atype in 'ZBCSI':
299 | return 'jint'
300 | elif atype == 'J':
301 | return 'jlong'
302 | elif atype == 'F':
303 | return 'jfloat'
304 | elif atype == 'D':
305 | return 'jdouble'
306 | else:
307 | return 'jobject'
308 |
309 |
310 | # art/runtime/utils.cc
311 | def MangleForJni(name):
312 | result = ''
313 | for ch in name:
314 | if ('A' <= ch <= 'Z') or ('a' <= ch <= 'z') or ('0' <= ch <= '9'):
315 | result += ch
316 | elif ch == '.' or ch == '/':
317 | result += "_"
318 | elif ch == '_':
319 | result += "_1"
320 | elif ch == ';':
321 | result += "_2"
322 | elif ch == '[':
323 | result += "_3"
324 | else:
325 | result += '_0%04x' % (ord(ch))
326 | return result
327 |
328 |
329 | def JniShortName(cls_name, method_name):
330 | assert cls_name[0] == 'L'
331 | assert cls_name[-1] == ';'
332 | cls_name = cls_name[1:-1]
333 | short_name = 'Java_'
334 | short_name += MangleForJni(cls_name)
335 | short_name += '_'
336 | short_name += MangleForJni(method_name)
337 | return short_name
338 |
339 |
340 | def JniLongName(cls_name, method_name, signature):
341 | long_name = ''
342 | long_name += JniShortName(cls_name, method_name)
343 | long_name += "__"
344 | signature = signature[1:]
345 | index = signature.find(')')
346 | long_name += MangleForJni(signature[:index])
347 | return long_name
348 |
349 |
350 | def compare_primitive_type(type1, type2):
351 | if type1 is None and type2 is None:
352 | return 0
353 | if type1 is None:
354 | # type1 < type2
355 | return -1
356 | elif type2 is None:
357 | # type1 > type2
358 | return 1
359 |
360 | assert is_primitive_type(type1)
361 | assert is_primitive_type(type2)
362 |
363 | o1 = PRIMITIVE_TYPE_ORDER.get(type1)
364 | o2 = PRIMITIVE_TYPE_ORDER.get(type2)
365 | return o1 - o2
366 |
367 |
368 | def get_smaller_type(type1, type2):
369 | return type1 if compare_primitive_type(type1, type2) < 0 else type2
370 |
371 |
372 | def get_bigger_type(type1, type2):
373 | return type1 if compare_primitive_type(type1, type2) > 0 else type2
374 |
375 |
376 | def merge_array_type(type1, type2):
377 | assert is_array(type1) or is_array(type2)
378 | if is_java_lang_object(type2):
379 | return type2
380 | elif is_java_lang_object(type1):
381 | return type1
382 | if is_array(type1):
383 | if is_array(type2):
384 | new_type = merge_type(type1[1:], type2[1:])
385 | if new_type:
386 | return '[' + new_type
387 | else:
388 | return None
389 | else:
390 | return 'Ljava/lang/Object;'
391 | else:
392 | return merge_array_type(type2, type1)
393 |
394 |
395 | # return bigger type
396 | def merge_reference_type(type1, type2):
397 | assert is_ref(type1) and is_ref(type2)
398 | if type1 == type2:
399 | return type1
400 | elif is_java_lang_object(type1) and is_ref(type2):
401 | return type1
402 | elif is_java_lang_object(type2) and is_ref(type1):
403 | return type2
404 | else:
405 | return 'Ljava/lang/Object;'
406 |
407 |
408 | def merge_type(type1, type2):
409 | if type1 is None and type2 is None:
410 | return None
411 | if type1 is None:
412 | return type2
413 | if type2 is None:
414 | return type1
415 |
416 | if (is_int(type1) and is_int(type2)) or \
417 | (is_float(type1) and is_float(type2)):
418 | return get_bigger_type(type1, type2)
419 | elif is_array(type1) or is_array(type2):
420 | new_type = merge_array_type(type1, type2)
421 | if new_type is None:
422 | return 'Ljava/lang/Object;'
423 | else:
424 | return new_type
425 | elif is_ref(type1) or is_ref(type2):
426 | return merge_reference_type(type1, type2)
427 | else:
428 | return None
429 |
430 |
431 | def is_synthetic_method(method):
432 | return method.get_access_flags() & 0x1000
433 |
434 |
435 | def is_native_method(method):
436 | return method.get_access_flags() & 0x100
437 |
438 |
439 | def hex_escape_string(s):
440 | result = ''
441 | s = s.encode('utf8')
442 | for c in s:
443 | result += '\\x%02x' % c
444 | return result
445 | # ERROR: hex escape sequence out of range
446 | # result = ''
447 | # s = s.encode('utf8')
448 | # for c in s:
449 | # if 0x20 <= c < 0x7f:
450 | # if c in (0x22, 0x27, 0x5c): # " ' \
451 | # result += '\\'
452 | # result += chr(c)
453 | # continue
454 | # if c < 0x20:
455 | # if c == 0x9:
456 | # result += '\\t'
457 | # elif c == 0xa:
458 | # result += '\\n'
459 | # elif c == 0xd:
460 | # result += '\\r'
461 | # else:
462 | # result += '\\x%02x' % c
463 | # continue
464 | # result += '\\x%02x' % c
465 | # return result
466 |
467 |
468 | def get_cdecl_name(clsname):
469 | assert is_ref(clsname)
470 | return clsname[1:-1].replace('/', '_').repace('[', '_')
471 |
472 |
473 | # ERROR: universal character name refers to a control character
474 | def string(s):
475 | """
476 | Convert a string to a escaped ASCII representation including quotation marks
477 | :param s: a string
478 | :return: ASCII escaped string
479 | """
480 | ret = []
481 | for c in s:
482 | if ' ' <= c < '\x7f':
483 | if c == "'" or c == '"' or c == '\\':
484 | ret.append('\\')
485 | ret.append(c)
486 | continue
487 | elif c <= '\x7f':
488 | if c in ('\r', '\n', '\t'):
489 | # unicode-escape produces bytes
490 | ret.append(c.encode('unicode-escape').decode("ascii"))
491 | continue
492 | i = ord(c)
493 | ret.append('\\u')
494 | ret.append('%x' % (i >> 12))
495 | ret.append('%x' % ((i >> 8) & 0x0f))
496 | ret.append('%x' % ((i >> 4) & 0x0f))
497 | ret.append('%x' % (i & 0x0f))
498 | return ''.join(ret)
499 |
--------------------------------------------------------------------------------
/dex2c/writer.py:
--------------------------------------------------------------------------------
1 | # encoding=utf8
2 | #
3 | # Copyright (c) 2012 Geoffroy Gueguen
4 | # All Rights Reserved.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # http://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS-IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 |
18 | import logging
19 | from builtins import object
20 | from builtins import range
21 | from builtins import zip
22 | from struct import unpack
23 |
24 | from dex2c import util
25 | from dex2c.instruction import BinaryCompExpression, Constant
26 | from dex2c.opcode_ins import Op
27 | from dex2c.util import get_type_descriptor, get_native_type, JniLongName, is_primitive_type, \
28 | get_cdecl_type, get_type
29 |
30 | logger = logging.getLogger('dex2c.writer')
31 |
32 |
33 | class TmpnameAllocator(object):
34 | def __init__(self, vars, prefix=''):
35 | self.numbering = {}
36 | self.next_name = 0
37 | self.prefix = prefix
38 | for item in vars:
39 | assert item is not None
40 | if item is None:
41 | raise Exception("Unable to allocate tmpname for None.")
42 | if item in self.numbering:
43 | continue
44 | else:
45 | self.numbering[item] = self.next_name
46 | self.next_name += 1
47 |
48 | def get_name(self, item):
49 | assert item and item in self.numbering
50 | logger.debug("%s - > %s%s" % (item, self.prefix, self.numbering[item]))
51 | return '%s%s' % (self.prefix, self.numbering[item])
52 |
53 |
54 | class Writer(object):
55 | def __init__(self, irmethod, dynamic_register):
56 | self.graph = irmethod.graph
57 | self.method = irmethod.method
58 | self.irmethod = irmethod
59 | self.visited_nodes = set()
60 | self.buffer = []
61 | self.dynamic_register = dynamic_register
62 | self.prototype = []
63 |
64 | entry = irmethod.entry
65 | self.ra = irmethod.ra
66 | self.ca = TmpnameAllocator(entry.class_to_declare, 'cls').get_name
67 | self.fa = TmpnameAllocator(entry.field_to_declare, 'fld').get_name
68 | self.ma = TmpnameAllocator(entry.method_to_declare, 'mth').get_name
69 |
70 | def __str__(self):
71 | return ''.join(self.buffer)
72 |
73 | def get_prototype(self):
74 | return ''.join(self.prototype)
75 |
76 | def write_trace(self, ins):
77 | s = ins.dump()
78 | if s:
79 | self.write('LOGD("%s");\n' % s)
80 |
81 | def write(self, s):
82 | self.buffer.append(s)
83 |
84 | def end_ins(self):
85 | self.write(';\n')
86 |
87 | def visit_ins(self, ins):
88 | ins.visit(self)
89 |
90 | def visit_move_param(self, ins):
91 | param = ins.get_param()
92 | value = param.get_value()
93 | self.write('v%s = (%s)' % (self.ra(value), get_cdecl_type(value.get_type())))
94 | param.visit(self)
95 | self.write(";\n")
96 |
97 | def write_method(self):
98 | access = util.get_access_method(self.method.get_access_flags())
99 | class_name = self.method.get_class_name()
100 | _, name, proto = self.method.get_triple()
101 |
102 | jni_name = JniLongName(class_name, name, proto)
103 |
104 | self.write("\n/* %s->%s%s */\n" % (class_name, name, proto))
105 |
106 | if self.dynamic_register:
107 | self.write(get_native_type(self.irmethod.rtype) + ' ')
108 | self.prototype.append(get_native_type(self.irmethod.rtype) + ' ')
109 | self.prototype.append(jni_name)
110 | else:
111 | self.write('extern "C" JNIEXPORT %s JNICALL\n' % get_native_type(self.irmethod.rtype))
112 |
113 | self.write(jni_name)
114 | params = self.irmethod.params
115 | if 'static' not in access:
116 | params = params[1:]
117 | proto = ''
118 | if self.irmethod.params_type:
119 | proto = ', '.join(['%s p%s' % (get_native_type(p_type), param) for p_type,
120 | param in
121 | zip(self.irmethod.params_type, params)])
122 | if proto:
123 | self.write('(JNIEnv *env, jobject thiz, %s)' % proto)
124 | if self.dynamic_register:
125 | self.prototype.append('(JNIEnv *env, jobject thiz, %s)' % proto)
126 | else:
127 | self.write('(JNIEnv *env, jobject thiz)')
128 | if self.dynamic_register:
129 | self.prototype.append('(JNIEnv *env, jobject thiz)')
130 | self.write('{\n')
131 | nodes = self.irmethod.irblocks
132 | for node in nodes:
133 | self.visit_node(node)
134 |
135 | for lp in self.irmethod.landing_pads:
136 | self.write('\n')
137 | self.visit_landing_pad(lp)
138 |
139 | return_type = self.irmethod.rtype
140 | if return_type[0] != 'V':
141 | if return_type[0] == 'L':
142 | self.write("EX_UnwindBlock: return NULL;\n")
143 | else:
144 | self.write("EX_UnwindBlock: return (%s)0;\n" % (get_native_type(return_type)))
145 | else:
146 | self.write("EX_UnwindBlock: return;\n")
147 |
148 | self.write('}\n')
149 |
150 | def visit_node(self, node):
151 | if node in self.visited_nodes:
152 | return
153 | self.visited_nodes.add(node)
154 | var_declared = set()
155 | for var in node.var_to_declare:
156 | var_type = var.get_type()
157 | r = self.ra(var)
158 | if r in var_declared:
159 | continue
160 | var_declared.add(r)
161 | self.write('%s v%s' % (get_cdecl_type(var_type), r))
162 | if util.is_ref(var_type):
163 | self.write(' = NULL')
164 | self.write(";\n")
165 |
166 | if node.var_to_declare and self.irmethod.landing_pads:
167 | self.write("jthrowable exception;\n")
168 |
169 | declared = set()
170 | to_declare = []
171 | for jclass in node.class_to_declare:
172 | if jclass in declared:
173 | continue
174 | declared.add(jclass)
175 | to_declare.append('%s = NULL' % (self.ca(jclass)))
176 | if to_declare:
177 | self.write('jclass %s;\n' % (','.join(to_declare)))
178 |
179 | declared.clear()
180 | to_declare.clear()
181 | for jfield in node.field_to_declare:
182 | if jfield in declared:
183 | continue
184 | declared.add(jfield)
185 | to_declare.append('%s = NULL' % (self.fa(jfield)))
186 | if to_declare:
187 | self.write('jfieldID %s;\n' % (','.join(to_declare)))
188 |
189 | declared.clear()
190 | to_declare.clear()
191 | for jmethod in node.method_to_declare:
192 | if jmethod in declared:
193 | continue
194 | declared.add(jmethod)
195 | to_declare.append('%s = NULL' % (self.ma(jmethod)))
196 | if to_declare:
197 | self.write('jmethodID %s;\n' % (', '.join(to_declare)))
198 |
199 | for ins in node.move_param_insns:
200 | ins.visit(self)
201 | node.visit(self)
202 |
203 | def visit_landing_pad(self, landing_pad):
204 | self.write("%s:\n" % (landing_pad.label))
205 | self.write("D2C_GET_PENDING_EX\n")
206 | for atype, handle in landing_pad.handles.items():
207 | self.write('if(d2c_is_instance_of(env, exception, "%s")) {\n' % (get_type(atype)))
208 | self.write('goto L%d;\n' % handle.num)
209 | self.write('}\n')
210 | self.write("D2C_GOTO_UNWINDBLOCK\n")
211 |
212 | def write_delete_dead_local_reference(self, val):
213 | if val.use_empty() and val.get_register() < 0:
214 | self.write_kill_local_reference(val, True)
215 |
216 | def write_kill_local_reference(self, val, tmp=False):
217 | if val is None:
218 | return
219 |
220 | if get_native_type(val.get_type()) in ('jarray', 'jobject', 'jstring'):
221 | if tmp or val.get_register() >= 0:
222 | reg = self.ra(val)
223 | self.write('if (v%s) {\n' % (reg))
224 | self.write('LOGD("env->DeleteLocalRef(%%p):v%s", v%s);\n' % (reg, reg))
225 | self.write('env->DeleteLocalRef(v%s);\n' % reg)
226 | self.write('}\n')
227 |
228 | def visit_switch_node(self, ins, switch, cases):
229 | self.write('switch (')
230 | switch.visit(self)
231 | self.write(') {\n')
232 | for case, offset in cases:
233 | node = self.irmethod.offset_to_node[offset + ins.offset]
234 | self.write('case %d: goto L%d;\n' % (case, node.num))
235 | self.write('}\n')
236 |
237 | def visit_statement_node(self, stmt):
238 | if stmt.num >= 0:
239 | self.write("L%d:\n" % stmt.num)
240 | for ins in stmt.get_instr_list():
241 | self.visit_ins(ins)
242 |
243 | def visit_return_node(self, ret):
244 | for ins in ret.get_ins():
245 | self.visit_ins(ins)
246 |
247 | def visit_load_constant(self, ins, obfus=False):
248 | val = ins.get_value()
249 | atype = val.get_type()
250 | self.write_trace(ins)
251 | self.write_kill_local_reference(val)
252 | cst = ins.get_cst().get_constant()
253 | cst_type = ins.get_cst().get_type()
254 | if atype == 'F':
255 | self.write('v%s = d2c_bitcast_to_float(%r);\n' % (self.ra(val), cst))
256 | elif atype == 'D':
257 | self.write('v%s = d2c_bitcast_to_double(%r);\n' % (self.ra(val), cst))
258 | elif cst_type == 'Ljava/lang/String;':
259 | c = 'v%s = (%s) env->NewStringUTF(AY_OBFUSCATE("%s"));\n' if obfus else 'v%s = (%s) env->NewStringUTF("%s");\n'
260 | self.write(
261 | c % (self.ra(val), get_native_type(atype), cst))
262 | elif cst_type == 'Ljava/lang/Class;':
263 | self.write('{\n')
264 | self.write_define_ex_handle(ins)
265 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
266 | self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (cst))
267 | self.write('v%s = env->NewLocalRef(clz);\n' % (self.ra(val)))
268 | self.write_undefine_ex_handle(ins)
269 | self.write('}\n')
270 | else:
271 | self.write('v%s = %r;\n' % (self.ra(val), cst))
272 |
273 | def visit_constant(self, cst):
274 | self.write('%s' % cst)
275 |
276 | def visit_variable(self, var):
277 | self.write('v%s' % self.ra(var))
278 |
279 | def visit_param(self, param):
280 | decl_type = get_native_type(param.get_type())
281 | if decl_type in ('jstring', 'jobject', 'jarray'):
282 | self.write('env->NewLocalRef(p%s)' % (param.get_register()))
283 | else:
284 | self.write('p%s' % param.get_register())
285 |
286 | def visit_this(self):
287 | self.write('env->NewLocalRef(thiz)')
288 |
289 | def visit_move_result(self, ins, lhs, rhs):
290 | self.write_trace(ins)
291 | self.write_kill_local_reference(ins.get_value())
292 | self.write('v%s = (%s) %s;\n' % (self.ra(lhs), get_cdecl_type(lhs.get_type()), self.get_variable_or_const(rhs)))
293 |
294 | def visit_move(self, lhs, rhs):
295 | self.write_kill_local_reference(lhs)
296 | self.write('v%s = ' % (self.ra(lhs)))
297 | if is_primitive_type(rhs.get_type()):
298 | self.write('%s' % (self.get_variable_or_const(rhs)))
299 | else:
300 | self.write('(%s) env->NewLocalRef(v%s)' % (get_cdecl_type(lhs.get_type()), self.ra(rhs)))
301 | self.write(';\n')
302 |
303 | def visit_astore(self, ins, array, index, rhs):
304 | self.write_trace(ins)
305 | self.write('{\n')
306 | self.write_define_ex_handle(ins)
307 | self.write_not_null(array)
308 | elem_type = ins.get_elem_type()
309 | if is_primitive_type(elem_type):
310 | self.write('{%s val = %s;' % (get_native_type(elem_type), self.get_variable_or_const(rhs)))
311 | self.write('env->Set%sArrayRegion((%sArray) v%s, (jint) %s, 1, &val);' %
312 | (get_type_descriptor(elem_type), get_native_type(elem_type),
313 | self.ra(array),
314 | self.get_variable_or_const(index)))
315 | self.write('}\n')
316 | else:
317 | self.write('env->SetObjectArrayElement((jobjectArray) v%s, (jint) %s, v%s);' %
318 | (self.ra(array),
319 | self.get_variable_or_const(index),
320 | self.ra(rhs)))
321 | self.write_undefine_ex_handle(ins)
322 | self.write('}\n')
323 |
324 | def visit_put_static(self, ins, clsdesc, name, ftype, rhs):
325 | self.write_trace(ins)
326 | self.write('{\n')
327 | self.write_define_ex_handle(ins)
328 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
329 | self.write('jfieldID &fld = %s;\n' % (self.fa(ins.get_field())))
330 | self.write('D2C_RESOLVE_STATIC_FIELD(clz, fld, "%s", "%s", "%s");\n' % (get_type(clsdesc), name, ftype))
331 | self.write('env->SetStatic%sField(clz,fld,(%s) %s);\n' % (
332 | get_type_descriptor(ftype), get_native_type(ftype), self.get_variable_or_const(rhs)))
333 | self.write_undefine_ex_handle(ins)
334 | self.write('}\n')
335 |
336 | def write_not_null(self, var):
337 | self.write('D2C_NOT_NULL(%s);\n' % (self.get_variable_or_const(var)))
338 |
339 | def visit_put_instance(self, ins, lhs, rhs, ftype, clsdesc, name):
340 | self.write_trace(ins)
341 | self.write('{\n')
342 | self.write_define_ex_handle(ins)
343 | self.write_not_null(lhs)
344 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
345 | self.write('jfieldID &fld = %s;\n' % (self.fa(ins.get_field())))
346 | self.write('D2C_RESOLVE_FIELD(clz, fld, "%s", "%s", "%s");\n' % (get_type(clsdesc), name, ftype))
347 | self.write('env->Set%sField(v%s,fld,(%s) %s);\n' % (
348 | get_type_descriptor(ftype), self.ra(lhs), get_native_type(ftype), self.get_variable_or_const(rhs)))
349 | self.write_undefine_ex_handle(ins)
350 | self.write('}\n')
351 |
352 | def visit_new(self, ins, result, atype):
353 | self.write_trace(ins)
354 | self.write('{\n')
355 | self.write_define_ex_handle(ins)
356 | # should kill local reference after D2C_RESOLVE_CLASS, since D2C_RESOLVE_CLASS may throw exception,
357 | # so this ref may be double killed in exception handle.
358 | self.write_kill_local_reference(ins.get_value())
359 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
360 | self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (get_type(atype)))
361 | self.write('v%s = (%s) env->AllocObject(clz);\n' % (self.ra(result), get_native_type(result.get_type())))
362 | self.write_undefine_ex_handle(ins)
363 | self.write('}\n')
364 |
365 | def _invoke_common(self, ins, invoke_type, name, base, ptype, rtype, args, clsdesc):
366 | self.write('{\n')
367 | self.write_define_ex_handle(ins)
368 | if invoke_type != 'static':
369 | self.write("D2C_NOT_NULL(v%s);\n" % (self.ra(base)))
370 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
371 | self.write('jmethodID &mid = %s;\n' % (self.ma(ins.get_call_method())))
372 | if invoke_type != 'static':
373 | self.write('D2C_RESOLVE_METHOD(clz, mid, "%s", "%s", "(%s)%s");\n' % (get_type(clsdesc), name, ''.join(ptype), rtype))
374 | else:
375 | self.write('D2C_RESOLVE_STATIC_METHOD(clz, mid, "%s", "%s", "(%s)%s");\n' % (get_type(clsdesc), name, ''.join(ptype), rtype))
376 | self.write('jvalue args[] = {')
377 | vars = []
378 | for arg, atype in zip(args, ptype):
379 | if atype[0] == 'L' or atype[0] == '[':
380 | vars.append('{.l = %s}' % (self.get_variable_or_const(arg)))
381 | elif atype[0] == 'Z':
382 | vars.append('{.z = (jboolean) %s}' % (self.get_variable_or_const(arg)))
383 | elif atype[0] == 'B':
384 | vars.append('{.b = (jbyte) %s}' % (self.get_variable_or_const(arg)))
385 | elif atype[0] == 'C':
386 | vars.append('{.c = (jchar) %s}' % (self.get_variable_or_const(arg)))
387 | elif atype[0] == 'S':
388 | vars.append('{.s = (jshort) %s}' % (self.get_variable_or_const(arg)))
389 | elif atype[0] == 'I':
390 | vars.append('{.i = %s}' % (self.get_variable_or_const(arg)))
391 | elif atype[0] == 'J':
392 | vars.append('{.j = (jlong) %s}' % (self.get_variable_or_const(arg)))
393 | elif atype[0] == 'F':
394 | vars.append('{.f = %s}' % (self.get_variable_or_const(arg)))
395 | elif atype[0] == 'D':
396 | vars.append('{.d = %s}' % (self.get_variable_or_const(arg)))
397 | else:
398 | raise Exception("Unknow signuare type %s" % (atype))
399 | self.write(','.join(vars))
400 | self.write('};\n')
401 | if rtype != 'V':
402 | self.write_kill_local_reference(ins.get_value())
403 | ins.get_value().visit(self)
404 | self.write(' = ')
405 | self.write("(%s) " % (get_native_type(ins.get_value().get_type())))
406 |
407 | if invoke_type == 'super':
408 | self.write(
409 | 'env->CallNonvirtual%sMethodA(v%s, clz, mid, args);\n' % (get_type_descriptor(rtype), self.ra(base)))
410 | elif invoke_type == 'static':
411 | self.write('env->CallStatic%sMethodA(clz, mid, args);\n' % (get_type_descriptor(rtype)))
412 | else:
413 | self.write('env->Call%sMethodA(v%s, mid, args);\n' % (get_type_descriptor(rtype), self.ra(base)))
414 |
415 | self.write_undefine_ex_handle(ins)
416 | self.write('}\n')
417 | if rtype != 'V':
418 | self.write_delete_dead_local_reference(ins.get_value())
419 |
420 | def visit_invoke(self, ins, invoke_type, name, base, ptype, rtype, args, clsdesc):
421 | self.write_trace(ins)
422 | return self._invoke_common(ins, invoke_type, name, base, ptype, rtype, args, clsdesc)
423 |
424 | def visit_return_void(self):
425 | self.write('return')
426 | self.end_ins()
427 |
428 | def visit_return(self, arg):
429 | return_type = self.irmethod.rtype
430 | if return_type[0] != 'V':
431 | self.write("return (%s) %s;\n" % (get_native_type(return_type), self.get_variable_or_const(arg)))
432 | else:
433 | self.write('return;')
434 |
435 | def visit_nop(self):
436 | pass
437 |
438 | def visit_goto(self, target):
439 | self.write('goto L%d' % (self.irmethod.offset_to_node[target].num))
440 | self.end_ins()
441 |
442 | def visit_check_cast(self, ins, arg, atype):
443 | self.write_trace(ins)
444 | self.write('{\n')
445 | self.write_define_ex_handle(ins)
446 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
447 | self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (get_type(atype)))
448 | self.write('D2C_CHECK_CAST(%s, clz, "%s");\n' % (self.get_variable_or_const(arg), get_type(atype)))
449 | self.write_undefine_ex_handle(ins)
450 | self.write('}\n')
451 |
452 | def visit_instanceof(self, ins, result, arg, atype):
453 | self.write_trace(ins)
454 | self.write('{\n')
455 | self.write_define_ex_handle(ins)
456 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
457 | self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (get_type(atype)))
458 | self.write('v%s = d2c_is_instance_of(env, v%s, clz);\n' % (self.ra(result), self.ra(arg)))
459 | self.write_undefine_ex_handle(ins)
460 | self.write('}\n')
461 |
462 | def visit_aload(self, ins, result, array, index):
463 | self.write_trace(ins)
464 | self.write('{\n')
465 | self.write_define_ex_handle(ins)
466 | self.write_not_null(array)
467 | elem_type = ins.get_elem_type()
468 | if is_primitive_type(elem_type):
469 | self.write('{%s val;' % (get_native_type(elem_type)))
470 | self.write('env->Get%sArrayRegion((%sArray) v%s, (jint) %s, 1, &val);' %
471 | (get_type_descriptor(elem_type), get_native_type(elem_type), self.ra(array),
472 | self.get_variable_or_const(index)))
473 | self.write('v%s = val;}' % (self.ra(result)))
474 | else:
475 | self.write_kill_local_reference(result)
476 | self.write('v%s = (%s) env->GetObjectArrayElement((jobjectArray) v%s, (jint) %s);' %
477 | (self.ra(result), get_native_type(result.get_type()),
478 | self.ra(array),
479 | self.get_variable_or_const(index)))
480 | self.write('\n')
481 | self.write_undefine_ex_handle(ins)
482 | self.write('}\n')
483 |
484 | def visit_alength(self, ins, result, array):
485 | self.write_trace(ins)
486 | self.write('{\n')
487 | self.write_define_ex_handle(ins)
488 | self.write_not_null(array)
489 | self.write('v%s = env->GetArrayLength((jarray) v%s);\n' % (self.ra(result), self.ra(array)))
490 | self.write_undefine_ex_handle(ins)
491 | self.write('}\n')
492 |
493 | def write_check_array_size(self, size):
494 | self.write('if (%s < 0) {\n'
495 | 'd2c_throw_exception(env, "java/lang/NegativeArraySizeException", "negative array size");\n'
496 | % self.get_variable_or_const(size))
497 | self.write('goto EX_HANDLE;\n')
498 | self.write('}\n')
499 |
500 | def visit_new_array(self, ins, result, atype, size):
501 | self.write_trace(ins)
502 | elem_type = ins.get_elem_type()
503 | self.write('{\n')
504 | self.write_define_ex_handle(ins)
505 | self.write_check_array_size(size)
506 | self.write_kill_local_reference(ins.get_value())
507 | if is_primitive_type(elem_type):
508 | result.visit(self)
509 | self.write(
510 | ' = (%s) env->New%sArray((jint) %s);\n' % (
511 | get_native_type(result.get_type()), get_type_descriptor(elem_type), self.get_variable_or_const(size)))
512 | else:
513 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
514 | self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (get_type(elem_type)))
515 | result.visit(self)
516 | self.write(' = env->NewObjectArray((jint) %s, clz, NULL);\n' % (self.get_variable_or_const(size)))
517 | self.write_undefine_ex_handle(ins)
518 | self.write('}\n')
519 |
520 | def visit_filled_new_array(self, ins, result, atype, size, args):
521 | self.write_trace(ins)
522 | params = []
523 | for arg in args:
524 | p = '%s' % (self.get_variable_or_const(arg))
525 | params.append(p)
526 | self.write('{\n')
527 | self.write_define_ex_handle(ins)
528 | self.write_kill_local_reference(ins.get_value())
529 | elem_type = atype[1:]
530 | assert elem_type != 'D' and elem_type != 'J'
531 | if is_primitive_type(elem_type):
532 | result.visit(self)
533 | self.write(' = env->New%sArray((jint) %r);\n' % (get_type_descriptor(elem_type), size))
534 | else:
535 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
536 | self.write('D2C_RESOLVE_CLASS(clz,"%s");\n' % (get_type(elem_type)))
537 | result.visit(self)
538 | self.write(' = env->NewObjectArray((jint) %r, clz, NULL);\n' % (size))
539 | self.write('d2c_filled_new_array(env, (jarray) v%s, "%s", %d, %s);\n'
540 | % (self.ra(result), elem_type, len(params), ', '.join(params)))
541 | self.write_undefine_ex_handle(ins)
542 | self.write('}\n')
543 |
544 | def visit_fill_array(self, ins, array, value):
545 | self.write_trace(ins)
546 | self.write('{\n')
547 | self.write('static const unsigned char data[] = {')
548 | data = value.get_data()
549 | tab = []
550 | elem_id = 'B'
551 | elem_size = 1
552 |
553 | for i in range(0, value.size * value.element_width, elem_size):
554 | tab.append('%s' % unpack(elem_id, data[i:i + elem_size])[0])
555 | self.write(', '.join(tab))
556 | self.write('};\n')
557 |
558 | elem_type = array.get_type()[1:]
559 | array_size = value.size
560 |
561 | self.write(
562 | 'env->Set%sArrayRegion((%sArray) v%s, 0, %d, (const %s *) data);\n' % (get_type_descriptor(elem_type), \
563 | get_native_type(elem_type),
564 | self.ra(array), \
565 | array_size,
566 | get_native_type(elem_type)))
567 | self.write('}\n')
568 |
569 | def visit_move_exception(self, ins, var):
570 | self.write_trace(ins)
571 | self.write_kill_local_reference(var)
572 | var.declared = True
573 | var.visit(self)
574 | self.write(' = exception;\n')
575 |
576 | def visit_monitor_enter(self, ins, ref):
577 | self.write_trace(ins)
578 | self.write('{\n')
579 | self.write_define_ex_handle(ins)
580 | self.write_not_null(ref)
581 | self.write('env->MonitorEnter(%s);\n' % (self.get_variable_or_const(ref)))
582 | self.write_undefine_ex_handle(ins)
583 | self.write('}\n')
584 |
585 | def visit_monitor_exit(self, ins, ref):
586 | self.write('{\n')
587 | self.write_define_ex_handle(ins)
588 | self.write('if (env->MonitorExit(%s) != JNI_OK) {\n' % (self.get_variable_or_const(ref)))
589 | self.write_undefine_ex_handle(ins)
590 | self.write('}\n')
591 | self.write('}\n')
592 |
593 | def visit_throw(self, ins, ref):
594 | self.write_trace(ins)
595 | self.write('{\n')
596 | self.write_define_ex_handle(ins)
597 | self.write_not_null(ref)
598 | self.write('env->Throw((jthrowable) v%s);\n' % self.ra(ref))
599 | self.write_undefine_ex_handle(ins)
600 | self.write('}\n')
601 |
602 | def write_div_expression(self, ins, result, op, arg1, arg2):
603 | self.write('{\n')
604 | if result.get_type() not in 'FD':
605 | self.write_define_ex_handle(ins)
606 | self.write('if (%s == 0) {\n'
607 | 'd2c_throw_exception(env, "java/lang/ArithmeticException", "divide by zero");\n'
608 | % self.get_variable_or_const(arg2))
609 | self.write('goto EX_HANDLE;\n')
610 | self.write('}\n')
611 | self.write('#undef EX_HANDLE\n')
612 | self.write('v%s = ' % (self.ra(result)))
613 | arg1.visit(self)
614 | self.write(' %s ' % (op))
615 | arg2.visit(self)
616 | self.write(';\n')
617 | self.write('}\n')
618 |
619 | def visit_binary_expression(self, ins, result, op, arg1, arg2):
620 | self.write_trace(ins)
621 | if op == Op.DIV or op == Op.MOD:
622 | self.write_div_expression(ins, result, op, arg1, arg2)
623 | return
624 |
625 | self.write('v%s = ' % self.ra(result))
626 | # 浮点数有个NaN值,任何值与他比较都不成立,包括NaN.
627 | if op == Op.CMP:
628 | self.write('(')
629 | arg1.visit(self)
630 | self.write(' == ')
631 | arg2.visit(self)
632 | self.write(') ? 0 :')
633 | self.write(' (')
634 | arg1.visit(self)
635 | self.write(' > ')
636 | arg2.visit(self)
637 | self.write(') ? 1 : -1;\n')
638 | elif op == Op.CMPL:
639 | self.write('(')
640 | arg1.visit(self)
641 | self.write(' == ')
642 | arg2.visit(self)
643 | self.write(') ? 0 :')
644 | self.write(' (')
645 | arg1.visit(self)
646 | self.write(' > ')
647 | arg2.visit(self)
648 | self.write(') ? 1 : -1;\n')
649 | elif op == Op.CMPG:
650 | self.write('(')
651 | arg1.visit(self)
652 | self.write(' == ')
653 | arg2.visit(self)
654 | self.write(') ? 0 :')
655 | self.write(' (')
656 | arg1.visit(self)
657 | self.write(' < ')
658 | arg2.visit(self)
659 | self.write(') ? -1 : 1;\n')
660 | elif op == Op.INTSHR:
661 | self.write('(%s) >> (' % (self.get_variable_or_const(arg1)))
662 | arg2.visit(self)
663 | self.write(' & 0x1f);\n')
664 | elif op == Op.INTSHL:
665 | self.write('(%s) << (' % (self.get_variable_or_const(arg1)))
666 | arg2.visit(self)
667 | self.write(' & 0x1f);\n')
668 | elif op == Op.INTUSHR:
669 | self.write('((uint32_t) %s) >> (' % (self.get_variable_or_const(arg1)))
670 | arg2.visit(self)
671 | self.write(' & 0x1f);\n')
672 | elif op == Op.LONGSHR:
673 | self.write('(v%s) >> (' % (self.ra(arg1)))
674 | arg2.visit(self)
675 | self.write(' & 0x3f);\n')
676 | elif op == Op.LONGSHL:
677 | self.write('(%s) << (' % (self.get_variable_or_const(arg1)))
678 | arg2.visit(self)
679 | self.write(' & 0x3f);\n')
680 | elif op == Op.LONGUSHR:
681 | self.write('((uint64_t) v%s) >> (' % (self.ra(arg1)))
682 | arg2.visit(self)
683 | self.write(' & 0x3f);\n')
684 | elif op == Op.MODF:
685 | self.write('fmodf(v%s, v%s);\n' % (self.ra(arg1), self.ra(arg2)))
686 | elif op == Op.MODD:
687 | self.write('fmod(v%s, v%s);\n' % (self.ra(arg1), self.ra(arg2)))
688 | else:
689 | self.write('(')
690 | arg1.visit(self)
691 | self.write(' %s ' % op)
692 | arg2.visit(self)
693 | self.write(');\n')
694 |
695 | def visit_unary_expression(self, ins, result, op, arg):
696 | self.write_trace(ins)
697 | self.write('v%s = (%s %s);\n' % (self.ra(result), op, self.get_variable_or_const(arg)))
698 |
699 | def visit_cast(self, lhs, op, arg):
700 | type1 = arg.get_type()
701 | type2 = lhs.get_type()
702 | # double to long
703 | if type1 == 'D' and type2 == 'J':
704 | self.write('v%s = d2c_double_to_long(v%s);\n' % (self.ra(lhs), self.ra(arg)))
705 | # double to int
706 | elif type1 == 'D' and type2 == 'I':
707 | self.write('v%s = d2c_double_to_int(v%s);\n' % (self.ra(lhs), self.ra(arg)))
708 | # float to long
709 | elif type1 == 'F' and type2 == 'J':
710 | self.write('v%s = d2c_float_to_long(v%s);\n' % (self.ra(lhs), self.ra(arg)))
711 | elif type1 == 'F' and type2 == 'I':
712 | self.write('v%s = d2c_float_to_int(v%s);\n' % (self.ra(lhs), self.ra(arg)))
713 | else:
714 | self.write('v%s = %s(%s);\n' % (self.ra(lhs), op, self.get_variable_or_const(arg)))
715 |
716 | def visit_cond_expression(self, ins, op, arg1, arg2, true_target, false_target):
717 | self.write_trace(ins)
718 | true_target_node = self.irmethod.offset_to_node[true_target]
719 | false_target_node = self.irmethod.offset_to_node[false_target]
720 | self.write('if(')
721 | if is_primitive_type(arg1.get_type()):
722 | arg1.visit(self)
723 | self.write(' %s ' % op)
724 | arg2.visit(self)
725 | else:
726 | if op == '!=':
727 | self.write('!')
728 | self.write('d2c_is_same_object(env,')
729 | arg1.visit(self)
730 | self.write(',')
731 | arg2.visit(self)
732 | self.write(')')
733 | self.write(') ')
734 | self.write('{\n')
735 | self.write('goto L%d;\n' % true_target_node.num)
736 | self.write('}\n')
737 | self.write('else {\n')
738 | self.write('goto L%d;\n' % false_target_node.num)
739 | self.write('}\n')
740 |
741 | def visit_condz_expression(self, ins, op, arg, true_target, false_target):
742 | self.write_trace(ins)
743 | true_target_node = self.irmethod.offset_to_node[true_target]
744 | false_target_node = self.irmethod.offset_to_node[false_target]
745 | if isinstance(arg, BinaryCompExpression):
746 | arg.op = op
747 | return arg.visit(self)
748 | atype = arg.get_type()
749 | self.write('if(')
750 | arg.visit(self)
751 | if atype in 'ZBSCIJFD':
752 | self.write(' %s 0' % op)
753 | else:
754 | self.write(' %s NULL' % op)
755 | self.write(')')
756 | self.write('{\n')
757 | self.write('goto L%d;\n' % (true_target_node.num))
758 | self.write('}\n')
759 | self.write('else {\n')
760 | self.write('goto L%d;\n' % (false_target_node.num))
761 | self.write('}\n')
762 |
763 | def visit_get_instance(self, ins, result, arg, ftype, clsdesc, name):
764 | self.write_trace(ins)
765 | self.write('{\n')
766 | self.write_define_ex_handle(ins)
767 | self.write_not_null(arg)
768 | self.write_kill_local_reference(result)
769 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
770 | self.write('jfieldID &fld = %s;\n' % (self.fa(ins.get_field())))
771 | self.write('D2C_RESOLVE_FIELD(clz, fld, "%s", "%s", "%s");\n' % (get_type(clsdesc), name, ftype))
772 | result.visit(self)
773 | self.write(
774 | ' = (%s) env->Get%sField(v%s,fld);\n' % (
775 | get_native_type(result.get_type()), get_type_descriptor(ftype), self.ra(arg)))
776 | self.write_undefine_ex_handle(ins)
777 | self.write('}\n')
778 |
779 | def write_define_ex_handle(self, ins):
780 | bb = ins.parent
781 | if bb in self.irmethod.node_to_landing_pad:
782 | landing_pad = self.irmethod.node_to_landing_pad[ins.parent].label
783 | else:
784 | landing_pad = 'EX_UnwindBlock'
785 | self.write("#define EX_HANDLE %s\n" % (landing_pad))
786 |
787 | def write_undefine_ex_handle(self, ins):
788 | self.write('D2C_CHECK_PENDING_EX;\n')
789 | self.write('#undef EX_HANDLE\n')
790 |
791 | def visit_get_static(self, ins, result, ftype, clsdesc, name):
792 | self.write_trace(ins)
793 | self.write('{\n')
794 | self.write_define_ex_handle(ins)
795 | self.write_kill_local_reference(result)
796 | self.write('jclass &clz = %s;\n' % (self.ca(ins.get_class())))
797 | self.write('jfieldID &fld = %s;\n' % (self.fa(ins.get_field())))
798 | self.write('D2C_RESOLVE_STATIC_FIELD(clz, fld, "%s", "%s", "%s");\n' % (get_type(clsdesc), name, ftype))
799 | result.visit(self)
800 | self.write(' = (%s) env->GetStatic%sField(clz,fld);\n' % (
801 | get_native_type(result.get_type()), get_type_descriptor(ftype)))
802 | self.write_undefine_ex_handle(ins)
803 | self.write('}\n')
804 |
805 | def get_variable_or_const(self, var):
806 | if isinstance(var, Constant):
807 | return '%s' % var
808 | else:
809 | return 'v%s' % self.ra(var)
810 |
--------------------------------------------------------------------------------
/filter.txt:
--------------------------------------------------------------------------------
1 | # Rules are made using regex patterns
2 |
3 | # Protect all methods in all classes
4 | # Not recommended for real world applications.
5 | #.*
6 |
--------------------------------------------------------------------------------
/keystore/debug.keystore:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Kirlif/d2c/80305482722efd38781d9213a7cc20b7bc036eed/keystore/debug.keystore
--------------------------------------------------------------------------------
/loader/DccApplication.smali:
--------------------------------------------------------------------------------
1 | .class public Lamimo/dcc/DccApplication;
2 | .super Landroid/app/Application;
3 |
4 |
5 | # direct methods
6 | .method static final constructor ()V
7 | .locals 1
8 |
9 | const-string v0, "stub"
10 |
11 | invoke-static {v0}, Ljava/lang/System;->loadLibrary(Ljava/lang/String;)V
12 |
13 | return-void
14 | .end method
15 |
16 | .method public constructor ()V
17 | .locals 0
18 |
19 | invoke-direct {p0}, Landroid/app/Application;->()V
20 |
21 | return-void
22 | .end method
23 |
24 |
25 |
--------------------------------------------------------------------------------
/project/jni/Android.mk:
--------------------------------------------------------------------------------
1 | LOCAL_PATH := $(call my-dir)
2 |
3 | include $(CLEAR_VARS)
4 | LOCAL_MODULE := stub
5 | LOCAL_LDLIBS := -llog
6 |
7 | SOURCES:= $(wildcard $(LOCAL_PATH)/nc/*.cpp)
8 | LOCAL_C_INCLUDES := $(LOCAL_PATH)/nc
9 |
10 | LOCAL_SRC_FILES := $(SOURCES:$(LOCAL_PATH)/%=%)
11 |
12 | include $(BUILD_SHARED_LIBRARY)
13 |
--------------------------------------------------------------------------------
/project/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_STL := c++_static
2 | APP_CPPFLAGS += -fvisibility=hidden
3 | APP_PLATFORM := 21
4 | APP_ABI := armeabi-v7a arm64-v8a # x86 x86_64
5 |
6 |
--------------------------------------------------------------------------------
/project/jni/nc/Dex2C.cpp:
--------------------------------------------------------------------------------
1 | #include "Dex2C.h"
2 |
3 | #include
4 | #include
5 |
6 | #include