├── .gitignore
├── LICENSE
├── README.md
├── app
├── .gitignore
├── build.gradle.kts
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── test
│ │ └── ptrace_il2cppdumper
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ └── cpp
│ │ ├── CMakeLists.txt
│ │ ├── hack.cpp
│ │ ├── hack.h
│ │ ├── il2cpp-api-functions.h
│ │ ├── il2cpp-class.h
│ │ ├── il2cpp-tabledefs.h
│ │ ├── il2cpp_dump.cpp
│ │ ├── il2cpp_dump.h
│ │ ├── log.h
│ │ └── xdl
│ │ ├── include
│ │ └── xdl.h
│ │ ├── xdl.c
│ │ ├── xdl_iterate.c
│ │ ├── xdl_iterate.h
│ │ ├── xdl_linker.c
│ │ ├── xdl_linker.h
│ │ ├── xdl_lzma.c
│ │ ├── xdl_lzma.h
│ │ ├── xdl_util.c
│ │ └── xdl_util.h
│ └── test
│ └── java
│ └── com
│ └── test
│ └── ptrace_il2cppdumper
│ └── ExampleUnitTest.java
├── build.gradle.kts
├── gradle.properties
├── gradle
├── libs.versions.toml
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── ida.py
└── settings.gradle.kts
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 |
635 | Copyright (C)
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | Copyright (C)
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PtraceIl2cppDumper
2 | 一个用于在安卓平台上通过主动调用对unity游戏进行dump的so模块。
3 |
4 | # 如何使用
5 | ~~先在目标手游的/data/data/packageName/files目录下创建test.txt文件,test.txt文件中的**每一行**均为要进行dump的程序集名称如Assembly-CSharp.dll,**注意这里创建以及写入test.txt文件务必在手机设备的环境上进行,否则可能会出现bug**。在创建/data/data/packageName/files/test.txt文件并写入要进行dump的程序集名称后即可~~
6 | 通过任意ptrace注入器将该so模块注入至要dump的unity游戏进程中,主动调用dump将自动执行。**最好是在游戏的相应逻辑触发后再进行注入,因为如果需要的类还未加载就不会被dump**。可在logcat中使用Perfare进行过滤查看结果。如dump成功会在/data/data/packageName/files目录下生成test.cs以及test_method_info.txt文件。
7 |
8 | ~~目标unity手游的所有程序集名称均可在其apk包的assets\bin\Data\ScriptingAssemblies.json中找到。~~
9 | 推荐使用的ptrace注入器为[Android-Ptrace-Injector](https://github.com/reveny/Android-Ptrace-Injector)或[AndKittyInjector](https://github.com/MJx0/AndKittyInjector)。
10 |
11 | ## 新增ida.py脚本
12 | 使用ida加载libil2cpp.so后导入并执行ida.py脚本,再根据引导选择dump生成的test_method_info.txt文件即可重命名大部分函数。
13 |
14 |
15 | # 如何构建
16 | 克隆本项目后,使用androidStudio打开,然后等待项目配置自动完成,之后在本项目目录下使用**gradlew :app:externalNativeBuildRelease**命令进行编译,编译完成后会在<项目目录>\app\build\intermediates\cmake\release\obj\arm64-v8a下生成libtest.so文件。
17 |
18 |
19 |
20 | # 致谢
21 | 本项目基于[Zygisk-Il2CppDumper](https://github.com/Perfare/Zygisk-Il2CppDumper)
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/app/build.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | alias(libs.plugins.android.application)
3 | }
4 |
5 | android {
6 | namespace = "com.test.ptrace_il2cppdumper"
7 | compileSdk = 35
8 |
9 | defaultConfig {
10 | applicationId = "com.test.ptrace_il2cppdumper"
11 | minSdk = 29
12 | targetSdk = 35
13 | versionCode = 1
14 | versionName = "1.0"
15 |
16 | testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
17 | ndk {
18 | abiFilters.add("arm64-v8a") // 只编译 arm64 架构
19 | }
20 | }
21 |
22 | buildTypes {
23 | release {
24 | isMinifyEnabled = false
25 | proguardFiles(
26 | getDefaultProguardFile("proguard-android-optimize.txt"),
27 | "proguard-rules.pro"
28 | )
29 | }
30 | }
31 | compileOptions {
32 | sourceCompatibility = JavaVersion.VERSION_11
33 | targetCompatibility = JavaVersion.VERSION_11
34 | }
35 | externalNativeBuild {
36 | cmake {
37 | path = file("src/main/cpp/CMakeLists.txt")
38 | version = "3.22.1"
39 | }
40 | }
41 | buildFeatures {
42 | viewBinding = true
43 | }
44 | }
45 |
46 |
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/test/ptrace_il2cppdumper/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.test.ptrace_il2cppdumper;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("com.test.ptrace_il2cppdumper", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/cpp/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.18.1)
2 |
3 |
4 | set(MODULE_NAME "test")
5 |
6 | if (NOT DEFINED MODULE_NAME)
7 | message(FATAL_ERROR "MODULE_NAME is not set")
8 | else ()
9 | project(${MODULE_NAME})
10 | endif ()
11 |
12 |
13 | message("Build type: ${CMAKE_BUILD_TYPE}")
14 |
15 | set(CMAKE_CXX_STANDARD 20)
16 |
17 | set(LINKER_FLAGS "-ffixed-x18 -Wl,--hash-style=both")
18 | set(C_FLAGS "-Werror=format -fdata-sections -ffunction-sections")
19 | set(CXX_FLAGS "${CXX_FLAGS} -fno-exceptions -fno-rtti")
20 |
21 | if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
22 | set(C_FLAGS "${C_FLAGS} -O2 -fvisibility=hidden -fvisibility-inlines-hidden")
23 | set(LINKER_FLAGS "${LINKER_FLAGS} -Wl,-exclude-libs,ALL -Wl,--gc-sections -Wl,--strip-all")
24 | else ()
25 | set(C_FLAGS "${C_FLAGS} -O0")
26 | endif ()
27 |
28 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${C_FLAGS}")
29 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${C_FLAGS} ${CXX_FLAGS}")
30 |
31 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}")
32 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}")
33 |
34 | include_directories(
35 | xdl/include
36 | )
37 |
38 | aux_source_directory(xdl xdl-src)
39 |
40 | add_library(${MODULE_NAME} SHARED
41 | hack.cpp
42 | il2cpp_dump.cpp
43 | ${xdl-src})
44 | target_link_libraries(${MODULE_NAME} log)
45 |
46 | #if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
47 | # add_custom_command(TARGET ${MODULE_NAME} POST_BUILD
48 | # COMMAND ${CMAKE_STRIP} --strip-all --remove-section=.comment "${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/lib${MODULE_NAME}.so")
49 | #endif ()
50 |
--------------------------------------------------------------------------------
/app/src/main/cpp/hack.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Perfare on 2020/7/4.
3 | //
4 |
5 | #include "hack.h"
6 | #include "il2cpp_dump.h"
7 | #include "log.h"
8 | #include "xdl.h"
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 | #include
20 | #include
21 |
22 | char game_path[PATH_MAX];
23 |
24 | void hack_start(const char *game_data_dir) {
25 | bool load = false;
26 | for (int i = 0; i < 10; i++) {
27 | void *handle = xdl_open("libil2cpp.so", 0);
28 | if (handle) {
29 | load = true;
30 | il2cpp_api_init(handle);
31 | il2cpp_dump(game_data_dir);
32 | break;
33 | } else {
34 | sleep(1);
35 | }
36 | }
37 | if (!load) {
38 | LOGI("libil2cpp.so not found in thread %d", gettid());
39 | }
40 | }
41 |
42 | std::string GetLibDir(JavaVM *vms) {
43 | JNIEnv *env = nullptr;
44 | vms->AttachCurrentThread(&env, nullptr);
45 | jclass activity_thread_clz = env->FindClass("android/app/ActivityThread");
46 | if (activity_thread_clz != nullptr) {
47 | jmethodID currentApplicationId = env->GetStaticMethodID(activity_thread_clz,
48 | "currentApplication",
49 | "()Landroid/app/Application;");
50 | if (currentApplicationId) {
51 | jobject application = env->CallStaticObjectMethod(activity_thread_clz,
52 | currentApplicationId);
53 | jclass application_clazz = env->GetObjectClass(application);
54 | if (application_clazz) {
55 | jmethodID get_application_info = env->GetMethodID(application_clazz,
56 | "getApplicationInfo",
57 | "()Landroid/content/pm/ApplicationInfo;");
58 | if (get_application_info) {
59 | jobject application_info = env->CallObjectMethod(application,
60 | get_application_info);
61 | jfieldID native_library_dir_id = env->GetFieldID(
62 | env->GetObjectClass(application_info), "nativeLibraryDir",
63 | "Ljava/lang/String;");
64 | if (native_library_dir_id) {
65 | auto native_library_dir_jstring = (jstring) env->GetObjectField(
66 | application_info, native_library_dir_id);
67 | auto path = env->GetStringUTFChars(native_library_dir_jstring, nullptr);
68 | LOGI("lib dir %s", path);
69 | std::string lib_dir(path);
70 | env->ReleaseStringUTFChars(native_library_dir_jstring, path);
71 | return lib_dir;
72 | } else {
73 | LOGE("nativeLibraryDir not found");
74 | }
75 | } else {
76 | LOGE("getApplicationInfo not found");
77 | }
78 | } else {
79 | LOGE("application class not found");
80 | }
81 | } else {
82 | LOGE("currentApplication not found");
83 | }
84 | } else {
85 | LOGE("ActivityThread not found");
86 | }
87 | return {};
88 | }
89 |
90 | static std::string GetNativeBridgeLibrary() {
91 | auto value = std::array();
92 | __system_property_get("ro.dalvik.vm.native.bridge", value.data());
93 | return {value.data()};
94 | }
95 |
96 | struct NativeBridgeCallbacks {
97 | uint32_t version;
98 | void *initialize;
99 |
100 | void *(*loadLibrary)(const char *libpath, int flag);
101 |
102 | void *(*getTrampoline)(void *handle, const char *name, const char *shorty, uint32_t len);
103 |
104 | void *isSupported;
105 | void *getAppEnv;
106 | void *isCompatibleWith;
107 | void *getSignalHandler;
108 | void *unloadLibrary;
109 | void *getError;
110 | void *isPathSupported;
111 | void *initAnonymousNamespace;
112 | void *createNamespace;
113 | void *linkNamespaces;
114 |
115 | void *(*loadLibraryExt)(const char *libpath, int flag, void *ns);
116 | };
117 |
118 | bool NativeBridgeLoad(const char *game_data_dir, int api_level, void *data, size_t length) {
119 | //TODO 等待houdini初始化
120 | sleep(5);
121 |
122 | auto libart = dlopen("libart.so", RTLD_NOW);
123 | auto JNI_GetCreatedJavaVMs = (jint (*)(JavaVM **, jsize, jsize *)) dlsym(libart,
124 | "JNI_GetCreatedJavaVMs");
125 | LOGI("JNI_GetCreatedJavaVMs %p", JNI_GetCreatedJavaVMs);
126 | JavaVM *vms_buf[1];
127 | JavaVM *vms;
128 | jsize num_vms;
129 | jint status = JNI_GetCreatedJavaVMs(vms_buf, 1, &num_vms);
130 | if (status == JNI_OK && num_vms > 0) {
131 | vms = vms_buf[0];
132 | } else {
133 | LOGE("GetCreatedJavaVMs error");
134 | return false;
135 | }
136 |
137 | auto lib_dir = GetLibDir(vms);
138 | if (lib_dir.empty()) {
139 | LOGE("GetLibDir error");
140 | return false;
141 | }
142 | if (lib_dir.find("/lib/x86") != std::string::npos) {
143 | LOGI("no need NativeBridge");
144 | munmap(data, length);
145 | return false;
146 | }
147 |
148 | auto nb = dlopen("libhoudini.so", RTLD_NOW);
149 | if (!nb) {
150 | auto native_bridge = GetNativeBridgeLibrary();
151 | LOGI("native bridge: %s", native_bridge.data());
152 | nb = dlopen(native_bridge.data(), RTLD_NOW);
153 | }
154 | if (nb) {
155 | LOGI("nb %p", nb);
156 | auto callbacks = (NativeBridgeCallbacks *) dlsym(nb, "NativeBridgeItf");
157 | if (callbacks) {
158 | LOGI("NativeBridgeLoadLibrary %p", callbacks->loadLibrary);
159 | LOGI("NativeBridgeLoadLibraryExt %p", callbacks->loadLibraryExt);
160 | LOGI("NativeBridgeGetTrampoline %p", callbacks->getTrampoline);
161 |
162 | int fd = syscall(__NR_memfd_create, "anon", MFD_CLOEXEC);
163 | ftruncate(fd, (off_t) length);
164 | void *mem = mmap(nullptr, length, PROT_WRITE, MAP_SHARED, fd, 0);
165 | memcpy(mem, data, length);
166 | munmap(mem, length);
167 | munmap(data, length);
168 | char path[PATH_MAX];
169 | snprintf(path, PATH_MAX, "/proc/self/fd/%d", fd);
170 | LOGI("arm path %s", path);
171 |
172 | void *arm_handle;
173 | if (api_level >= 26) {
174 | arm_handle = callbacks->loadLibraryExt(path, RTLD_NOW, (void *) 3);
175 | } else {
176 | arm_handle = callbacks->loadLibrary(path, RTLD_NOW);
177 | }
178 | if (arm_handle) {
179 | LOGI("arm handle %p", arm_handle);
180 | auto init = (void (*)(JavaVM *, void *)) callbacks->getTrampoline(arm_handle,
181 | "JNI_OnLoad",
182 | nullptr, 0);
183 | LOGI("JNI_OnLoad %p", init);
184 | init(vms, (void *) game_data_dir);
185 | return true;
186 | }
187 | close(fd);
188 | }
189 | }
190 | return false;
191 | }
192 |
193 | void hack_prepare(const char *game_data_dir, void *data, size_t length) {
194 | LOGI("hack thread: %d", gettid());
195 | int api_level = android_get_device_api_level();
196 | LOGI("api level: %d", api_level);
197 |
198 | #if defined(__i386__) || defined(__x86_64__)
199 | if (!NativeBridgeLoad(game_data_dir, api_level, data, length)) {
200 | #endif
201 | hack_start(game_data_dir);
202 | #if defined(__i386__) || defined(__x86_64__)
203 | }
204 | #endif
205 | }
206 |
207 | #if defined(__arm__) || defined(__aarch64__)
208 |
209 |
210 |
211 | void start_dump(){
212 | LOGI("start dump.....");
213 | std::ifstream file("/proc/self/cmdline");
214 | if (!file.is_open()) {
215 | LOGE("Failed to open cmdline");
216 | return;
217 | }
218 |
219 | std::stringstream buffer;
220 | buffer << file.rdbuf(); // 读取文件内容到 stringstream
221 | file.close();
222 |
223 | snprintf(game_path, PATH_MAX, "/data/data/%s",buffer.str().c_str());
224 | LOGI("game dir:%s\n", game_path);
225 | std::thread hack_thread(hack_start, game_path);
226 | hack_thread.detach();
227 | }
228 | __attribute__((section(".init_array"))) void (*test_dump)() = start_dump;
229 |
230 |
231 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
232 | return JNI_VERSION_1_6;
233 | }
234 |
235 | #endif
--------------------------------------------------------------------------------
/app/src/main/cpp/hack.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Perfare on 2020/7/4.
3 | //
4 |
5 | #ifndef ZYGISK_IL2CPPDUMPER_HACK_H
6 | #define ZYGISK_IL2CPPDUMPER_HACK_H
7 |
8 | #include
9 |
10 | void hack_prepare(const char *game_data_dir, void *data, size_t length);
11 |
12 | #endif //ZYGISK_IL2CPPDUMPER_HACK_H
13 |
--------------------------------------------------------------------------------
/app/src/main/cpp/il2cpp-api-functions.h:
--------------------------------------------------------------------------------
1 | #ifndef DO_API_NO_RETURN
2 | #define DO_API_NO_RETURN(r, n, p) DO_API(r,n,p)
3 | #endif
4 |
5 | DO_API(int, il2cpp_init, (const char* domain_name));
6 | DO_API(int, il2cpp_init_utf16, (const Il2CppChar * domain_name));
7 | DO_API(void, il2cpp_shutdown, ());
8 | DO_API(void, il2cpp_set_config_dir, (const char *config_path));
9 | DO_API(void, il2cpp_set_data_dir, (const char *data_path));
10 | DO_API(void, il2cpp_set_temp_dir, (const char *temp_path));
11 | DO_API(void, il2cpp_set_commandline_arguments, (int argc, const char* const argv[], const char* basedir));
12 | DO_API(void, il2cpp_set_commandline_arguments_utf16, (int argc, const Il2CppChar * const argv[], const char* basedir));
13 | DO_API(void, il2cpp_set_config_utf16, (const Il2CppChar * executablePath));
14 | DO_API(void, il2cpp_set_config, (const char* executablePath));
15 |
16 | DO_API(void, il2cpp_set_memory_callbacks, (Il2CppMemoryCallbacks * callbacks));
17 | DO_API(const Il2CppImage*, il2cpp_get_corlib, ());
18 | DO_API(void, il2cpp_add_internal_call, (const char* name, Il2CppMethodPointer method));
19 | DO_API(Il2CppMethodPointer, il2cpp_resolve_icall, (const char* name));
20 |
21 | DO_API(void*, il2cpp_alloc, (size_t size));
22 | DO_API(void, il2cpp_free, (void* ptr));
23 |
24 | // array
25 | DO_API(Il2CppClass*, il2cpp_array_class_get, (Il2CppClass * element_class, uint32_t rank));
26 | DO_API(uint32_t, il2cpp_array_length, (Il2CppArray * array));
27 | DO_API(uint32_t, il2cpp_array_get_byte_length, (Il2CppArray * array));
28 | DO_API(Il2CppArray*, il2cpp_array_new, (Il2CppClass * elementTypeInfo, il2cpp_array_size_t length));
29 | DO_API(Il2CppArray*, il2cpp_array_new_specific, (Il2CppClass * arrayTypeInfo, il2cpp_array_size_t length));
30 | DO_API(Il2CppArray*, il2cpp_array_new_full, (Il2CppClass * array_class, il2cpp_array_size_t * lengths, il2cpp_array_size_t * lower_bounds));
31 | DO_API(Il2CppClass*, il2cpp_bounded_array_class_get, (Il2CppClass * element_class, uint32_t rank, bool bounded));
32 | DO_API(int, il2cpp_array_element_size, (const Il2CppClass * array_class));
33 |
34 | // assembly
35 | DO_API(const Il2CppImage*, il2cpp_assembly_get_image, (const Il2CppAssembly * assembly));
36 |
37 | // class
38 | DO_API(void, il2cpp_class_for_each, (void(*klassReportFunc)(Il2CppClass* klass, void* userData), void* userData));
39 | DO_API(const Il2CppType*, il2cpp_class_enum_basetype, (Il2CppClass * klass));
40 | DO_API(bool, il2cpp_class_is_generic, (const Il2CppClass * klass));
41 | DO_API(bool, il2cpp_class_is_inflated, (const Il2CppClass * klass));
42 | DO_API(bool, il2cpp_class_is_assignable_from, (Il2CppClass * klass, Il2CppClass * oklass));
43 | DO_API(bool, il2cpp_class_is_subclass_of, (Il2CppClass * klass, Il2CppClass * klassc, bool check_interfaces));
44 | DO_API(bool, il2cpp_class_has_parent, (Il2CppClass * klass, Il2CppClass * klassc));
45 | DO_API(Il2CppClass*, il2cpp_class_from_il2cpp_type, (const Il2CppType * type));
46 | DO_API(Il2CppClass*, il2cpp_class_from_name, (const Il2CppImage * image, const char* namespaze, const char *name));
47 | DO_API(Il2CppClass*, il2cpp_class_from_system_type, (Il2CppReflectionType * type));
48 | DO_API(Il2CppClass*, il2cpp_class_get_element_class, (Il2CppClass * klass));
49 | DO_API(const EventInfo*, il2cpp_class_get_events, (Il2CppClass * klass, void* *iter));
50 | DO_API(FieldInfo*, il2cpp_class_get_fields, (Il2CppClass * klass, void* *iter));
51 | DO_API(Il2CppClass*, il2cpp_class_get_nested_types, (Il2CppClass * klass, void* *iter));
52 | DO_API(Il2CppClass*, il2cpp_class_get_interfaces, (Il2CppClass * klass, void* *iter));
53 | DO_API(const PropertyInfo*, il2cpp_class_get_properties, (Il2CppClass * klass, void* *iter));
54 | DO_API(const PropertyInfo*, il2cpp_class_get_property_from_name, (Il2CppClass * klass, const char *name));
55 | DO_API(FieldInfo*, il2cpp_class_get_field_from_name, (Il2CppClass * klass, const char *name));
56 | DO_API(const MethodInfo*, il2cpp_class_get_methods, (Il2CppClass * klass, void* *iter));
57 | DO_API(const MethodInfo*, il2cpp_class_get_method_from_name, (Il2CppClass * klass, const char* name, int argsCount));
58 | DO_API(const char*, il2cpp_class_get_name, (Il2CppClass * klass));
59 | DO_API(void, il2cpp_type_get_name_chunked, (const Il2CppType * type, void(*chunkReportFunc)(void* data, void* userData), void* userData));
60 | DO_API(const char*, il2cpp_class_get_namespace, (Il2CppClass * klass));
61 | DO_API(Il2CppClass*, il2cpp_class_get_parent, (Il2CppClass * klass));
62 | DO_API(Il2CppClass*, il2cpp_class_get_declaring_type, (Il2CppClass * klass));
63 | DO_API(int32_t, il2cpp_class_instance_size, (Il2CppClass * klass));
64 | DO_API(size_t, il2cpp_class_num_fields, (const Il2CppClass * enumKlass));
65 | DO_API(bool, il2cpp_class_is_valuetype, (const Il2CppClass * klass));
66 | DO_API(int32_t, il2cpp_class_value_size, (Il2CppClass * klass, uint32_t * align));
67 | DO_API(bool, il2cpp_class_is_blittable, (const Il2CppClass * klass));
68 | DO_API(int, il2cpp_class_get_flags, (const Il2CppClass * klass));
69 | DO_API(bool, il2cpp_class_is_abstract, (const Il2CppClass * klass));
70 | DO_API(bool, il2cpp_class_is_interface, (const Il2CppClass * klass));
71 | DO_API(int, il2cpp_class_array_element_size, (const Il2CppClass * klass));
72 | DO_API(Il2CppClass*, il2cpp_class_from_type, (const Il2CppType * type));
73 | DO_API(const Il2CppType*, il2cpp_class_get_type, (Il2CppClass * klass));
74 | DO_API(uint32_t, il2cpp_class_get_type_token, (Il2CppClass * klass));
75 | DO_API(bool, il2cpp_class_has_attribute, (Il2CppClass * klass, Il2CppClass * attr_class));
76 | DO_API(bool, il2cpp_class_has_references, (Il2CppClass * klass));
77 | DO_API(bool, il2cpp_class_is_enum, (const Il2CppClass * klass));
78 | DO_API(const Il2CppImage*, il2cpp_class_get_image, (Il2CppClass * klass));
79 | DO_API(const char*, il2cpp_class_get_assemblyname, (const Il2CppClass * klass));
80 | DO_API(int, il2cpp_class_get_rank, (const Il2CppClass * klass));
81 | DO_API(uint32_t, il2cpp_class_get_data_size, (const Il2CppClass * klass));
82 | DO_API(void*, il2cpp_class_get_static_field_data, (const Il2CppClass * klass));
83 |
84 | // testing only
85 | DO_API(size_t, il2cpp_class_get_bitmap_size, (const Il2CppClass * klass));
86 | DO_API(void, il2cpp_class_get_bitmap, (Il2CppClass * klass, size_t * bitmap));
87 |
88 | // stats
89 | DO_API(bool, il2cpp_stats_dump_to_file, (const char *path));
90 | DO_API(uint64_t, il2cpp_stats_get_value, (Il2CppStat stat));
91 |
92 | // domain
93 | DO_API(Il2CppDomain*, il2cpp_domain_get, ());
94 | DO_API(const Il2CppAssembly*, il2cpp_domain_assembly_open, (Il2CppDomain * domain, const char* name));
95 | DO_API(const Il2CppAssembly**, il2cpp_domain_get_assemblies, (const Il2CppDomain * domain, size_t * size));
96 |
97 | // exception
98 | DO_API_NO_RETURN(void, il2cpp_raise_exception, (Il2CppException*));
99 | DO_API(Il2CppException*, il2cpp_exception_from_name_msg, (const Il2CppImage * image, const char *name_space, const char *name, const char *msg));
100 | DO_API(Il2CppException*, il2cpp_get_exception_argument_null, (const char *arg));
101 | DO_API(void, il2cpp_format_exception, (const Il2CppException * ex, char* message, int message_size));
102 | DO_API(void, il2cpp_format_stack_trace, (const Il2CppException * ex, char* output, int output_size));
103 | DO_API(void, il2cpp_unhandled_exception, (Il2CppException*));
104 | DO_API(void, il2cpp_native_stack_trace, (const Il2CppException * ex, uintptr_t** addresses, int* numFrames, char** imageUUID, char** imageName));
105 |
106 | // field
107 | DO_API(int, il2cpp_field_get_flags, (FieldInfo * field));
108 | DO_API(const char*, il2cpp_field_get_name, (FieldInfo * field));
109 | DO_API(Il2CppClass*, il2cpp_field_get_parent, (FieldInfo * field));
110 | DO_API(size_t, il2cpp_field_get_offset, (FieldInfo * field));
111 | DO_API(const Il2CppType*, il2cpp_field_get_type, (FieldInfo * field));
112 | DO_API(void, il2cpp_field_get_value, (Il2CppObject * obj, FieldInfo * field, void *value));
113 | DO_API(Il2CppObject*, il2cpp_field_get_value_object, (FieldInfo * field, Il2CppObject * obj));
114 | DO_API(bool, il2cpp_field_has_attribute, (FieldInfo * field, Il2CppClass * attr_class));
115 | DO_API(void, il2cpp_field_set_value, (Il2CppObject * obj, FieldInfo * field, void *value));
116 | DO_API(void, il2cpp_field_static_get_value, (FieldInfo * field, void *value));
117 | DO_API(void, il2cpp_field_static_set_value, (FieldInfo * field, void *value));
118 | DO_API(void, il2cpp_field_set_value_object, (Il2CppObject * instance, FieldInfo * field, Il2CppObject * value));
119 | DO_API(bool, il2cpp_field_is_literal, (FieldInfo * field));
120 | // gc
121 | DO_API(void, il2cpp_gc_collect, (int maxGenerations));
122 | DO_API(int32_t, il2cpp_gc_collect_a_little, ());
123 | DO_API(void, il2cpp_gc_start_incremental_collection , ());
124 | DO_API(void, il2cpp_gc_disable, ());
125 | DO_API(void, il2cpp_gc_enable, ());
126 | DO_API(bool, il2cpp_gc_is_disabled, ());
127 | DO_API(void, il2cpp_gc_set_mode, (Il2CppGCMode mode));
128 | DO_API(int64_t, il2cpp_gc_get_max_time_slice_ns, ());
129 | DO_API(void, il2cpp_gc_set_max_time_slice_ns, (int64_t maxTimeSlice));
130 | DO_API(bool, il2cpp_gc_is_incremental, ());
131 | DO_API(int64_t, il2cpp_gc_get_used_size, ());
132 | DO_API(int64_t, il2cpp_gc_get_heap_size, ());
133 | DO_API(void, il2cpp_gc_wbarrier_set_field, (Il2CppObject * obj, void **targetAddress, void *object));
134 | DO_API(bool, il2cpp_gc_has_strict_wbarriers, ());
135 | DO_API(void, il2cpp_gc_set_external_allocation_tracker, (void(*func)(void*, size_t, int)));
136 | DO_API(void, il2cpp_gc_set_external_wbarrier_tracker, (void(*func)(void**)));
137 | DO_API(void, il2cpp_gc_foreach_heap, (void(*func)(void* data, void* userData), void* userData));
138 | DO_API(void, il2cpp_stop_gc_world, ());
139 | DO_API(void, il2cpp_start_gc_world, ());
140 | DO_API(void*, il2cpp_gc_alloc_fixed, (size_t size));
141 | DO_API(void, il2cpp_gc_free_fixed, (void* address));
142 | // gchandle
143 | DO_API(uint32_t, il2cpp_gchandle_new, (Il2CppObject * obj, bool pinned));
144 | DO_API(uint32_t, il2cpp_gchandle_new_weakref, (Il2CppObject * obj, bool track_resurrection));
145 | DO_API(Il2CppObject*, il2cpp_gchandle_get_target , (uint32_t gchandle));
146 | DO_API(void, il2cpp_gchandle_free, (uint32_t gchandle));
147 | DO_API(void , il2cpp_gchandle_foreach_get_target, (void(*func)(void* data, void* userData), void* userData));
148 |
149 | // vm runtime info
150 | DO_API(uint32_t, il2cpp_object_header_size, ());
151 | DO_API(uint32_t, il2cpp_array_object_header_size, ());
152 | DO_API(uint32_t, il2cpp_offset_of_array_length_in_array_object_header, ());
153 | DO_API(uint32_t, il2cpp_offset_of_array_bounds_in_array_object_header, ());
154 | DO_API(uint32_t, il2cpp_allocation_granularity, ());
155 |
156 | // liveness
157 | DO_API(void*, il2cpp_unity_liveness_allocate_struct, (Il2CppClass * filter, int max_object_count, il2cpp_register_object_callback callback, void* userdata, il2cpp_liveness_reallocate_callback reallocate));
158 | DO_API(void, il2cpp_unity_liveness_calculation_from_root, (Il2CppObject * root, void* state));
159 | DO_API(void, il2cpp_unity_liveness_calculation_from_statics, (void* state));
160 | DO_API(void, il2cpp_unity_liveness_finalize, (void* state));
161 | DO_API(void, il2cpp_unity_liveness_free_struct, (void* state));
162 |
163 | // method
164 | DO_API(const Il2CppType*, il2cpp_method_get_return_type, (const MethodInfo * method));
165 | DO_API(Il2CppClass*, il2cpp_method_get_declaring_type, (const MethodInfo * method));
166 | DO_API(const char*, il2cpp_method_get_name, (const MethodInfo * method));
167 | DO_API(const MethodInfo*, il2cpp_method_get_from_reflection, (const Il2CppReflectionMethod * method));
168 | DO_API(Il2CppReflectionMethod*, il2cpp_method_get_object, (const MethodInfo * method, Il2CppClass * refclass));
169 | DO_API(bool, il2cpp_method_is_generic, (const MethodInfo * method));
170 | DO_API(bool, il2cpp_method_is_inflated, (const MethodInfo * method));
171 | DO_API(bool, il2cpp_method_is_instance, (const MethodInfo * method));
172 | DO_API(uint32_t, il2cpp_method_get_param_count, (const MethodInfo * method));
173 | DO_API(const Il2CppType*, il2cpp_method_get_param, (const MethodInfo * method, uint32_t index));
174 | DO_API(Il2CppClass*, il2cpp_method_get_class, (const MethodInfo * method));
175 | DO_API(bool, il2cpp_method_has_attribute, (const MethodInfo * method, Il2CppClass * attr_class));
176 | DO_API(uint32_t, il2cpp_method_get_flags, (const MethodInfo * method, uint32_t * iflags));
177 | DO_API(uint32_t, il2cpp_method_get_token, (const MethodInfo * method));
178 | DO_API(const char*, il2cpp_method_get_param_name, (const MethodInfo * method, uint32_t index));
179 |
180 | // profiler
181 | #if IL2CPP_ENABLE_PROFILER
182 |
183 | DO_API(void, il2cpp_profiler_install, (Il2CppProfiler * prof, Il2CppProfileFunc shutdown_callback));
184 | DO_API(void, il2cpp_profiler_set_events, (Il2CppProfileFlags events));
185 | DO_API(void, il2cpp_profiler_install_enter_leave, (Il2CppProfileMethodFunc enter, Il2CppProfileMethodFunc fleave));
186 | DO_API(void, il2cpp_profiler_install_allocation, (Il2CppProfileAllocFunc callback));
187 | DO_API(void, il2cpp_profiler_install_gc, (Il2CppProfileGCFunc callback, Il2CppProfileGCResizeFunc heap_resize_callback));
188 | DO_API(void, il2cpp_profiler_install_fileio, (Il2CppProfileFileIOFunc callback));
189 | DO_API(void, il2cpp_profiler_install_thread, (Il2CppProfileThreadFunc start, Il2CppProfileThreadFunc end));
190 |
191 | #endif
192 |
193 | // property
194 | DO_API(uint32_t, il2cpp_property_get_flags, (PropertyInfo * prop));
195 | DO_API(const MethodInfo*, il2cpp_property_get_get_method, (PropertyInfo * prop));
196 | DO_API(const MethodInfo*, il2cpp_property_get_set_method, (PropertyInfo * prop));
197 | DO_API(const char*, il2cpp_property_get_name, (PropertyInfo * prop));
198 | DO_API(Il2CppClass*, il2cpp_property_get_parent, (PropertyInfo * prop));
199 |
200 | // object
201 | DO_API(Il2CppClass*, il2cpp_object_get_class, (Il2CppObject * obj));
202 | DO_API(uint32_t, il2cpp_object_get_size, (Il2CppObject * obj));
203 | DO_API(const MethodInfo*, il2cpp_object_get_virtual_method, (Il2CppObject * obj, const MethodInfo * method));
204 | DO_API(Il2CppObject*, il2cpp_object_new, (const Il2CppClass * klass));
205 | DO_API(void*, il2cpp_object_unbox, (Il2CppObject * obj));
206 |
207 | DO_API(Il2CppObject*, il2cpp_value_box, (Il2CppClass * klass, void* data));
208 |
209 | // monitor
210 | DO_API(void, il2cpp_monitor_enter, (Il2CppObject * obj));
211 | DO_API(bool, il2cpp_monitor_try_enter, (Il2CppObject * obj, uint32_t timeout));
212 | DO_API(void, il2cpp_monitor_exit, (Il2CppObject * obj));
213 | DO_API(void, il2cpp_monitor_pulse, (Il2CppObject * obj));
214 | DO_API(void, il2cpp_monitor_pulse_all, (Il2CppObject * obj));
215 | DO_API(void, il2cpp_monitor_wait, (Il2CppObject * obj));
216 | DO_API(bool, il2cpp_monitor_try_wait, (Il2CppObject * obj, uint32_t timeout));
217 |
218 | // runtime
219 | DO_API(Il2CppObject*, il2cpp_runtime_invoke, (const MethodInfo * method, void *obj, void **params, Il2CppException **exc));
220 | DO_API(Il2CppObject*, il2cpp_runtime_invoke_convert_args, (const MethodInfo * method, void *obj, Il2CppObject **params, int paramCount, Il2CppException **exc));
221 | DO_API(void, il2cpp_runtime_class_init, (Il2CppClass * klass));
222 | DO_API(void, il2cpp_runtime_object_init, (Il2CppObject * obj));
223 |
224 | DO_API(void, il2cpp_runtime_object_init_exception, (Il2CppObject * obj, Il2CppException** exc));
225 |
226 | DO_API(void, il2cpp_runtime_unhandled_exception_policy_set, (Il2CppRuntimeUnhandledExceptionPolicy value));
227 |
228 | // string
229 | DO_API(int32_t, il2cpp_string_length, (Il2CppString * str));
230 | DO_API(Il2CppChar*, il2cpp_string_chars, (Il2CppString * str));
231 | DO_API(Il2CppString*, il2cpp_string_new, (const char* str));
232 | DO_API(Il2CppString*, il2cpp_string_new_len, (const char* str, uint32_t length));
233 | DO_API(Il2CppString*, il2cpp_string_new_utf16, (const Il2CppChar * text, int32_t len));
234 | DO_API(Il2CppString*, il2cpp_string_new_wrapper, (const char* str));
235 | DO_API(Il2CppString*, il2cpp_string_intern, (Il2CppString * str));
236 | DO_API(Il2CppString*, il2cpp_string_is_interned, (Il2CppString * str));
237 |
238 | // thread
239 | DO_API(Il2CppThread*, il2cpp_thread_current, ());
240 | DO_API(Il2CppThread*, il2cpp_thread_attach, (Il2CppDomain * domain));
241 | DO_API(void, il2cpp_thread_detach, (Il2CppThread * thread));
242 |
243 | DO_API(Il2CppThread**, il2cpp_thread_get_all_attached_threads, (size_t * size));
244 | DO_API(bool, il2cpp_is_vm_thread, (Il2CppThread * thread));
245 |
246 | // stacktrace
247 | DO_API(void, il2cpp_current_thread_walk_frame_stack, (Il2CppFrameWalkFunc func, void* user_data));
248 | DO_API(void, il2cpp_thread_walk_frame_stack, (Il2CppThread * thread, Il2CppFrameWalkFunc func, void* user_data));
249 | DO_API(bool, il2cpp_current_thread_get_top_frame, (Il2CppStackFrameInfo * frame));
250 | DO_API(bool, il2cpp_thread_get_top_frame, (Il2CppThread * thread, Il2CppStackFrameInfo * frame));
251 | DO_API(bool, il2cpp_current_thread_get_frame_at, (int32_t offset, Il2CppStackFrameInfo * frame));
252 | DO_API(bool, il2cpp_thread_get_frame_at, (Il2CppThread * thread, int32_t offset, Il2CppStackFrameInfo * frame));
253 | DO_API(int32_t, il2cpp_current_thread_get_stack_depth, ());
254 | DO_API(int32_t, il2cpp_thread_get_stack_depth, (Il2CppThread * thread));
255 | DO_API(void, il2cpp_override_stack_backtrace, (Il2CppBacktraceFunc stackBacktraceFunc));
256 |
257 | // type
258 | DO_API(Il2CppObject*, il2cpp_type_get_object, (const Il2CppType * type));
259 | DO_API(int, il2cpp_type_get_type, (const Il2CppType * type));
260 | DO_API(Il2CppClass*, il2cpp_type_get_class_or_element_class, (const Il2CppType * type));
261 | DO_API(char*, il2cpp_type_get_name, (const Il2CppType * type));
262 | DO_API(bool, il2cpp_type_is_byref, (const Il2CppType * type));
263 | DO_API(uint32_t, il2cpp_type_get_attrs, (const Il2CppType * type));
264 | DO_API(bool, il2cpp_type_equals, (const Il2CppType * type, const Il2CppType * otherType));
265 | DO_API(char*, il2cpp_type_get_assembly_qualified_name, (const Il2CppType * type));
266 | DO_API(bool, il2cpp_type_is_static, (const Il2CppType * type));
267 | DO_API(bool, il2cpp_type_is_pointer_type, (const Il2CppType * type));
268 |
269 | // image
270 | DO_API(const Il2CppAssembly*, il2cpp_image_get_assembly, (const Il2CppImage * image));
271 | DO_API(const char*, il2cpp_image_get_name, (const Il2CppImage * image));
272 | DO_API(const char*, il2cpp_image_get_filename, (const Il2CppImage * image));
273 | DO_API(const MethodInfo*, il2cpp_image_get_entry_point, (const Il2CppImage * image));
274 |
275 | DO_API(size_t, il2cpp_image_get_class_count, (const Il2CppImage * image));
276 | DO_API(const Il2CppClass*, il2cpp_image_get_class, (const Il2CppImage * image, size_t index));
277 |
278 | // Memory information
279 | DO_API(Il2CppManagedMemorySnapshot*, il2cpp_capture_memory_snapshot, ());
280 | DO_API(void, il2cpp_free_captured_memory_snapshot, (Il2CppManagedMemorySnapshot * snapshot));
281 |
282 | DO_API(void, il2cpp_set_find_plugin_callback, (Il2CppSetFindPlugInCallback method));
283 |
284 | // Logging
285 | DO_API(void, il2cpp_register_log_callback, (Il2CppLogCallback method));
286 |
287 | // Debugger
288 | DO_API(void, il2cpp_debugger_set_agent_options, (const char* options));
289 | DO_API(bool, il2cpp_is_debugger_attached, ());
290 | DO_API(void, il2cpp_register_debugger_agent_transport, (Il2CppDebuggerTransport * debuggerTransport));
291 |
292 | // Debug metadata
293 | DO_API(bool, il2cpp_debug_get_method_info, (const MethodInfo*, Il2CppMethodDebugInfo * methodDebugInfo));
294 |
295 | // TLS module
296 | DO_API(void, il2cpp_unity_install_unitytls_interface, (const void* unitytlsInterfaceStruct));
297 |
298 | // custom attributes
299 | DO_API(Il2CppCustomAttrInfo*, il2cpp_custom_attrs_from_class, (Il2CppClass * klass));
300 | DO_API(Il2CppCustomAttrInfo*, il2cpp_custom_attrs_from_method, (const MethodInfo * method));
301 |
302 | DO_API(Il2CppObject*, il2cpp_custom_attrs_get_attr, (Il2CppCustomAttrInfo * ainfo, Il2CppClass * attr_klass));
303 | DO_API(bool, il2cpp_custom_attrs_has_attr, (Il2CppCustomAttrInfo * ainfo, Il2CppClass * attr_klass));
304 | DO_API(Il2CppArray*, il2cpp_custom_attrs_construct, (Il2CppCustomAttrInfo * cinfo));
305 |
306 | DO_API(void, il2cpp_custom_attrs_free, (Il2CppCustomAttrInfo * ainfo));
307 |
308 | // Il2CppClass user data for GetComponent optimization
309 | DO_API(void, il2cpp_class_set_userdata, (Il2CppClass * klass, void* userdata));
310 | DO_API(int, il2cpp_class_get_userdata_offset, ());
311 |
312 | DO_API(void, il2cpp_set_default_thread_affinity, (int64_t affinity_mask));
313 |
--------------------------------------------------------------------------------
/app/src/main/cpp/il2cpp-class.h:
--------------------------------------------------------------------------------
1 | typedef uint16_t Il2CppChar;
2 | typedef uintptr_t il2cpp_array_size_t;
3 | typedef int32_t TypeDefinitionIndex;
4 | typedef int32_t GenericParameterIndex;
5 | typedef char Il2CppNativeChar;
6 |
7 | typedef struct Il2CppMemoryCallbacks Il2CppMemoryCallbacks;
8 | typedef struct Il2CppImage Il2CppImage;
9 | typedef struct Il2CppClass Il2CppClass;
10 | typedef struct Il2CppArrayBounds Il2CppArrayBounds;
11 | typedef struct Il2CppAssembly Il2CppAssembly;
12 | typedef struct Il2CppArrayType Il2CppArrayType;
13 | typedef struct Il2CppGenericClass Il2CppGenericClass;
14 | typedef struct Il2CppReflectionType Il2CppReflectionType;
15 | typedef struct MonitorData MonitorData;
16 | typedef Il2CppClass Il2CppVTable;
17 | typedef struct EventInfo EventInfo;
18 | typedef struct FieldInfo FieldInfo;
19 | typedef struct PropertyInfo PropertyInfo;
20 | typedef struct Il2CppDomain Il2CppDomain;
21 | typedef struct Il2CppException Il2CppException;
22 | typedef struct Il2CppObject Il2CppObject;
23 | typedef struct Il2CppReflectionMethod Il2CppReflectionMethod;
24 | typedef struct Il2CppString Il2CppString;
25 | typedef struct Il2CppThread Il2CppThread;
26 | typedef struct Il2CppStackFrameInfo Il2CppStackFrameInfo;
27 | typedef struct Il2CppManagedMemorySnapshot Il2CppManagedMemorySnapshot;
28 | typedef struct Il2CppDebuggerTransport Il2CppDebuggerTransport;
29 | typedef struct Il2CppMethodDebugInfo Il2CppMethodDebugInfo;
30 | typedef struct Il2CppCustomAttrInfo Il2CppCustomAttrInfo;
31 | typedef const struct ___Il2CppMetadataTypeHandle *Il2CppMetadataTypeHandle;
32 | typedef const struct ___Il2CppMetadataGenericParameterHandle *Il2CppMetadataGenericParameterHandle;
33 |
34 | typedef void (*Il2CppMethodPointer)();
35 |
36 | typedef void (*il2cpp_register_object_callback)(Il2CppObject **arr, int size, void *userdata);
37 |
38 | typedef void *(*il2cpp_liveness_reallocate_callback)(void *ptr, size_t size, void *userdata);
39 |
40 | typedef void (*Il2CppFrameWalkFunc)(const Il2CppStackFrameInfo *info, void *user_data);
41 |
42 | typedef size_t(*Il2CppBacktraceFunc)(Il2CppMethodPointer *buffer, size_t maxSize);
43 |
44 | typedef const Il2CppNativeChar *(*Il2CppSetFindPlugInCallback)(const Il2CppNativeChar *);
45 |
46 | typedef void (*Il2CppLogCallback)(const char *);
47 |
48 | typedef enum {
49 | IL2CPP_UNHANDLED_POLICY_LEGACY,
50 | IL2CPP_UNHANDLED_POLICY_CURRENT
51 | } Il2CppRuntimeUnhandledExceptionPolicy;
52 |
53 | typedef enum {
54 | IL2CPP_GC_MODE_DISABLED = 0,
55 | IL2CPP_GC_MODE_ENABLED = 1,
56 | IL2CPP_GC_MODE_MANUAL = 2
57 | } Il2CppGCMode;
58 |
59 | typedef enum Il2CppStat {
60 | IL2CPP_STAT_NEW_OBJECT_COUNT,
61 | IL2CPP_STAT_INITIALIZED_CLASS_COUNT,
62 | IL2CPP_STAT_METHOD_COUNT,
63 | IL2CPP_STAT_CLASS_STATIC_DATA_SIZE,
64 | IL2CPP_STAT_GENERIC_INSTANCE_COUNT,
65 | IL2CPP_STAT_GENERIC_CLASS_COUNT,
66 | IL2CPP_STAT_INFLATED_METHOD_COUNT,
67 | IL2CPP_STAT_INFLATED_TYPE_COUNT,
68 | } Il2CppStat;
69 |
70 | typedef enum Il2CppTypeEnum {
71 | IL2CPP_TYPE_END = 0x00,
72 | IL2CPP_TYPE_VOID = 0x01,
73 | IL2CPP_TYPE_BOOLEAN = 0x02,
74 | IL2CPP_TYPE_CHAR = 0x03,
75 | IL2CPP_TYPE_I1 = 0x04,
76 | IL2CPP_TYPE_U1 = 0x05,
77 | IL2CPP_TYPE_I2 = 0x06,
78 | IL2CPP_TYPE_U2 = 0x07,
79 | IL2CPP_TYPE_I4 = 0x08,
80 | IL2CPP_TYPE_U4 = 0x09,
81 | IL2CPP_TYPE_I8 = 0x0a,
82 | IL2CPP_TYPE_U8 = 0x0b,
83 | IL2CPP_TYPE_R4 = 0x0c,
84 | IL2CPP_TYPE_R8 = 0x0d,
85 | IL2CPP_TYPE_STRING = 0x0e,
86 | IL2CPP_TYPE_PTR = 0x0f,
87 | IL2CPP_TYPE_BYREF = 0x10,
88 | IL2CPP_TYPE_VALUETYPE = 0x11,
89 | IL2CPP_TYPE_CLASS = 0x12,
90 | IL2CPP_TYPE_VAR = 0x13,
91 | IL2CPP_TYPE_ARRAY = 0x14,
92 | IL2CPP_TYPE_GENERICINST = 0x15,
93 | IL2CPP_TYPE_TYPEDBYREF = 0x16,
94 | IL2CPP_TYPE_I = 0x18,
95 | IL2CPP_TYPE_U = 0x19,
96 | IL2CPP_TYPE_FNPTR = 0x1b,
97 | IL2CPP_TYPE_OBJECT = 0x1c,
98 | IL2CPP_TYPE_SZARRAY = 0x1d,
99 | IL2CPP_TYPE_MVAR = 0x1e,
100 | IL2CPP_TYPE_CMOD_REQD = 0x1f,
101 | IL2CPP_TYPE_CMOD_OPT = 0x20,
102 | IL2CPP_TYPE_INTERNAL = 0x21,
103 | IL2CPP_TYPE_MODIFIER = 0x40,
104 | IL2CPP_TYPE_SENTINEL = 0x41,
105 | IL2CPP_TYPE_PINNED = 0x45,
106 | IL2CPP_TYPE_ENUM = 0x55,
107 | IL2CPP_TYPE_IL2CPP_TYPE_INDEX = 0xff
108 | } Il2CppTypeEnum;
109 |
110 | typedef struct Il2CppType {
111 | union {
112 | void *dummy;
113 | TypeDefinitionIndex klassIndex;
114 | const Il2CppType *type;
115 | Il2CppArrayType *array;
116 | GenericParameterIndex genericParameterIndex;
117 | Il2CppGenericClass *generic_class;
118 | } data;
119 | unsigned int attrs: 16;
120 | Il2CppTypeEnum type: 8;
121 | unsigned int num_mods: 6;
122 | unsigned int byref: 1;
123 | unsigned int pinned: 1;
124 | } Il2CppType;
125 |
126 | typedef struct MethodInfo {
127 | Il2CppMethodPointer methodPointer;
128 | } MethodInfo;
129 |
130 | typedef struct Il2CppObject {
131 | union {
132 | Il2CppClass *klass;
133 | Il2CppVTable *vtable;
134 | };
135 | MonitorData *monitor;
136 | } Il2CppObject;
137 |
138 | typedef struct Il2CppArray {
139 | Il2CppObject obj;
140 | Il2CppArrayBounds *bounds;
141 | il2cpp_array_size_t max_length;
142 | void *vector[32];
143 | } Il2CppArray;
144 |
--------------------------------------------------------------------------------
/app/src/main/cpp/il2cpp-tabledefs.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | /*
4 | * Field Attributes (21.1.5).
5 | */
6 |
7 | #define FIELD_ATTRIBUTE_FIELD_ACCESS_MASK 0x0007
8 | #define FIELD_ATTRIBUTE_COMPILER_CONTROLLED 0x0000
9 | #define FIELD_ATTRIBUTE_PRIVATE 0x0001
10 | #define FIELD_ATTRIBUTE_FAM_AND_ASSEM 0x0002
11 | #define FIELD_ATTRIBUTE_ASSEMBLY 0x0003
12 | #define FIELD_ATTRIBUTE_FAMILY 0x0004
13 | #define FIELD_ATTRIBUTE_FAM_OR_ASSEM 0x0005
14 | #define FIELD_ATTRIBUTE_PUBLIC 0x0006
15 |
16 | #define FIELD_ATTRIBUTE_STATIC 0x0010
17 | #define FIELD_ATTRIBUTE_INIT_ONLY 0x0020
18 | #define FIELD_ATTRIBUTE_LITERAL 0x0040
19 | #define FIELD_ATTRIBUTE_NOT_SERIALIZED 0x0080
20 | #define FIELD_ATTRIBUTE_SPECIAL_NAME 0x0200
21 | #define FIELD_ATTRIBUTE_PINVOKE_IMPL 0x2000
22 |
23 | /* For runtime use only */
24 | #define FIELD_ATTRIBUTE_RESERVED_MASK 0x9500
25 | #define FIELD_ATTRIBUTE_RT_SPECIAL_NAME 0x0400
26 | #define FIELD_ATTRIBUTE_HAS_FIELD_MARSHAL 0x1000
27 | #define FIELD_ATTRIBUTE_HAS_DEFAULT 0x8000
28 | #define FIELD_ATTRIBUTE_HAS_FIELD_RVA 0x0100
29 |
30 | /*
31 | * Method Attributes (22.1.9)
32 | */
33 |
34 | #define METHOD_IMPL_ATTRIBUTE_CODE_TYPE_MASK 0x0003
35 | #define METHOD_IMPL_ATTRIBUTE_IL 0x0000
36 | #define METHOD_IMPL_ATTRIBUTE_NATIVE 0x0001
37 | #define METHOD_IMPL_ATTRIBUTE_OPTIL 0x0002
38 | #define METHOD_IMPL_ATTRIBUTE_RUNTIME 0x0003
39 |
40 | #define METHOD_IMPL_ATTRIBUTE_MANAGED_MASK 0x0004
41 | #define METHOD_IMPL_ATTRIBUTE_UNMANAGED 0x0004
42 | #define METHOD_IMPL_ATTRIBUTE_MANAGED 0x0000
43 |
44 | #define METHOD_IMPL_ATTRIBUTE_FORWARD_REF 0x0010
45 | #define METHOD_IMPL_ATTRIBUTE_PRESERVE_SIG 0x0080
46 | #define METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL 0x1000
47 | #define METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED 0x0020
48 | #define METHOD_IMPL_ATTRIBUTE_NOINLINING 0x0008
49 | #define METHOD_IMPL_ATTRIBUTE_MAX_METHOD_IMPL_VAL 0xffff
50 |
51 | #define METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK 0x0007
52 | #define METHOD_ATTRIBUTE_COMPILER_CONTROLLED 0x0000
53 | #define METHOD_ATTRIBUTE_PRIVATE 0x0001
54 | #define METHOD_ATTRIBUTE_FAM_AND_ASSEM 0x0002
55 | #define METHOD_ATTRIBUTE_ASSEM 0x0003
56 | #define METHOD_ATTRIBUTE_FAMILY 0x0004
57 | #define METHOD_ATTRIBUTE_FAM_OR_ASSEM 0x0005
58 | #define METHOD_ATTRIBUTE_PUBLIC 0x0006
59 |
60 | #define METHOD_ATTRIBUTE_STATIC 0x0010
61 | #define METHOD_ATTRIBUTE_FINAL 0x0020
62 | #define METHOD_ATTRIBUTE_VIRTUAL 0x0040
63 | #define METHOD_ATTRIBUTE_HIDE_BY_SIG 0x0080
64 |
65 | #define METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK 0x0100
66 | #define METHOD_ATTRIBUTE_REUSE_SLOT 0x0000
67 | #define METHOD_ATTRIBUTE_NEW_SLOT 0x0100
68 |
69 | #define METHOD_ATTRIBUTE_STRICT 0x0200
70 | #define METHOD_ATTRIBUTE_ABSTRACT 0x0400
71 | #define METHOD_ATTRIBUTE_SPECIAL_NAME 0x0800
72 |
73 | #define METHOD_ATTRIBUTE_PINVOKE_IMPL 0x2000
74 | #define METHOD_ATTRIBUTE_UNMANAGED_EXPORT 0x0008
75 |
76 | /*
77 | * For runtime use only
78 | */
79 | #define METHOD_ATTRIBUTE_RESERVED_MASK 0xd000
80 | #define METHOD_ATTRIBUTE_RT_SPECIAL_NAME 0x1000
81 | #define METHOD_ATTRIBUTE_HAS_SECURITY 0x4000
82 | #define METHOD_ATTRIBUTE_REQUIRE_SEC_OBJECT 0x8000
83 |
84 | /*
85 | * Type Attributes (21.1.13).
86 | */
87 | #define TYPE_ATTRIBUTE_VISIBILITY_MASK 0x00000007
88 | #define TYPE_ATTRIBUTE_NOT_PUBLIC 0x00000000
89 | #define TYPE_ATTRIBUTE_PUBLIC 0x00000001
90 | #define TYPE_ATTRIBUTE_NESTED_PUBLIC 0x00000002
91 | #define TYPE_ATTRIBUTE_NESTED_PRIVATE 0x00000003
92 | #define TYPE_ATTRIBUTE_NESTED_FAMILY 0x00000004
93 | #define TYPE_ATTRIBUTE_NESTED_ASSEMBLY 0x00000005
94 | #define TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM 0x00000006
95 | #define TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM 0x00000007
96 |
97 | #define TYPE_ATTRIBUTE_LAYOUT_MASK 0x00000018
98 | #define TYPE_ATTRIBUTE_AUTO_LAYOUT 0x00000000
99 | #define TYPE_ATTRIBUTE_SEQUENTIAL_LAYOUT 0x00000008
100 | #define TYPE_ATTRIBUTE_EXPLICIT_LAYOUT 0x00000010
101 |
102 | #define TYPE_ATTRIBUTE_CLASS_SEMANTIC_MASK 0x00000020
103 | #define TYPE_ATTRIBUTE_CLASS 0x00000000
104 | #define TYPE_ATTRIBUTE_INTERFACE 0x00000020
105 |
106 | #define TYPE_ATTRIBUTE_ABSTRACT 0x00000080
107 | #define TYPE_ATTRIBUTE_SEALED 0x00000100
108 | #define TYPE_ATTRIBUTE_SPECIAL_NAME 0x00000400
109 |
110 | #define TYPE_ATTRIBUTE_IMPORT 0x00001000
111 | #define TYPE_ATTRIBUTE_SERIALIZABLE 0x00002000
112 |
113 | #define TYPE_ATTRIBUTE_STRING_FORMAT_MASK 0x00030000
114 | #define TYPE_ATTRIBUTE_ANSI_CLASS 0x00000000
115 | #define TYPE_ATTRIBUTE_UNICODE_CLASS 0x00010000
116 | #define TYPE_ATTRIBUTE_AUTO_CLASS 0x00020000
117 |
118 | #define TYPE_ATTRIBUTE_BEFORE_FIELD_INIT 0x00100000
119 | #define TYPE_ATTRIBUTE_FORWARDER 0x00200000
120 |
121 | #define TYPE_ATTRIBUTE_RESERVED_MASK 0x00040800
122 | #define TYPE_ATTRIBUTE_RT_SPECIAL_NAME 0x00000800
123 | #define TYPE_ATTRIBUTE_HAS_SECURITY 0x00040000
124 |
125 | /*
126 | * Flags for Params (22.1.12)
127 | */
128 | #define PARAM_ATTRIBUTE_IN 0x0001
129 | #define PARAM_ATTRIBUTE_OUT 0x0002
130 | #define PARAM_ATTRIBUTE_OPTIONAL 0x0010
131 | #define PARAM_ATTRIBUTE_RESERVED_MASK 0xf000
132 | #define PARAM_ATTRIBUTE_HAS_DEFAULT 0x1000
133 | #define PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL 0x2000
134 | #define PARAM_ATTRIBUTE_UNUSED 0xcfe0
135 |
136 | // Flags for Generic Parameters (II.23.1.7)
137 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_NON_VARIANT 0x00
138 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_COVARIANT 0x01
139 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_CONTRAVARIANT 0x02
140 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_VARIANCE_MASK 0x03
141 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_REFERENCE_TYPE_CONSTRAINT 0x04
142 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_NOT_NULLABLE_VALUE_TYPE_CONSTRAINT 0x08
143 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_DEFAULT_CONSTRUCTOR_CONSTRAINT 0x10
144 | #define IL2CPP_GENERIC_PARAMETER_ATTRIBUTE_SPECIAL_CONSTRAINT_MASK 0x1C
145 |
146 | /**
147 | * 21.5 AssemblyRefs
148 | */
149 | #define ASSEMBLYREF_FULL_PUBLIC_KEY_FLAG 0x00000001
150 | #define ASSEMBLYREF_RETARGETABLE_FLAG 0x00000100
151 | #define ASSEMBLYREF_ENABLEJITCOMPILE_TRACKING_FLAG 0x00008000
152 | #define ASSEMBLYREF_DISABLEJITCOMPILE_OPTIMIZER_FLAG 0x00004000
153 |
--------------------------------------------------------------------------------
/app/src/main/cpp/il2cpp_dump.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Perfare on 2020/7/4.
3 | //
4 |
5 | #include "il2cpp_dump.h"
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include "xdl.h"
16 | #include "log.h"
17 | #include "il2cpp-tabledefs.h"
18 | #include "il2cpp-class.h"
19 |
20 | #define DO_API(r, n, p) r (*n) p
21 |
22 | #include "il2cpp-api-functions.h"
23 |
24 | #undef DO_API
25 |
26 |
27 | static uint64_t il2cpp_base = 0;
28 | std::stringstream method_info_outPut;
29 |
30 | void init_il2cpp_api(void *handle) {
31 | #define DO_API(r, n, p) { \
32 | n = (r (*) p)xdl_sym(handle, #n, nullptr); \
33 | if(!n) { \
34 | LOGW("api not found %s", #n); \
35 | } \
36 | }
37 |
38 | #include "il2cpp-api-functions.h"
39 |
40 | #undef DO_API
41 | }
42 |
43 | std::string get_method_modifier(uint32_t flags) {
44 | std::stringstream outPut;
45 | auto access = flags & METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK;
46 | switch (access) {
47 | case METHOD_ATTRIBUTE_PRIVATE:
48 | outPut << "private ";
49 | break;
50 | case METHOD_ATTRIBUTE_PUBLIC:
51 | outPut << "public ";
52 | break;
53 | case METHOD_ATTRIBUTE_FAMILY:
54 | outPut << "protected ";
55 | break;
56 | case METHOD_ATTRIBUTE_ASSEM:
57 | case METHOD_ATTRIBUTE_FAM_AND_ASSEM:
58 | outPut << "internal ";
59 | break;
60 | case METHOD_ATTRIBUTE_FAM_OR_ASSEM:
61 | outPut << "protected internal ";
62 | break;
63 | }
64 | if (flags & METHOD_ATTRIBUTE_STATIC) {
65 | outPut << "static ";
66 | }
67 | if (flags & METHOD_ATTRIBUTE_ABSTRACT) {
68 | outPut << "abstract ";
69 | if ((flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_REUSE_SLOT) {
70 | outPut << "override ";
71 | }
72 | } else if (flags & METHOD_ATTRIBUTE_FINAL) {
73 | if ((flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_REUSE_SLOT) {
74 | outPut << "sealed override ";
75 | }
76 | } else if (flags & METHOD_ATTRIBUTE_VIRTUAL) {
77 | if ((flags & METHOD_ATTRIBUTE_VTABLE_LAYOUT_MASK) == METHOD_ATTRIBUTE_NEW_SLOT) {
78 | outPut << "virtual ";
79 | } else {
80 | outPut << "override ";
81 | }
82 | }
83 | if (flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) {
84 | outPut << "extern ";
85 | }
86 | return outPut.str();
87 | }
88 |
89 | bool _il2cpp_type_is_byref(const Il2CppType *type) {
90 | auto byref = type->byref;
91 | if (il2cpp_type_is_byref) {
92 | byref = il2cpp_type_is_byref(type);
93 | }
94 | return byref;
95 | }
96 |
97 | std::string dump_method(Il2CppClass *klass) {
98 | std::stringstream outPut;
99 | outPut << "\n\t// Methods\n";
100 | void *iter = nullptr;
101 | while (auto method = il2cpp_class_get_methods(klass, &iter)) {
102 | //TODO attribute
103 | if (method->methodPointer) {
104 | outPut << "\t// RVA: 0x";
105 | outPut << std::hex << (uint64_t) method->methodPointer - il2cpp_base;
106 | method_info_outPut << std::hex << (uint64_t) method->methodPointer - il2cpp_base;
107 | outPut << " VA: 0x";
108 | outPut << std::hex << (uint64_t) method->methodPointer;
109 | } else {
110 | outPut << "\t// RVA: 0x VA: 0x0";
111 | }
112 | /*if (method->slot != 65535) {
113 | outPut << " Slot: " << std::dec << method->slot;
114 | }*/
115 | outPut << "\n\t";
116 | uint32_t iflags = 0;
117 | auto flags = il2cpp_method_get_flags(method, &iflags);
118 | outPut << get_method_modifier(flags);
119 | //TODO genericContainerIndex
120 | auto return_type = il2cpp_method_get_return_type(method);
121 | if (_il2cpp_type_is_byref(return_type)) {
122 | outPut << "ref ";
123 | }
124 | auto return_class = il2cpp_class_from_type(return_type);
125 | auto method_name = il2cpp_method_get_name(method);
126 | outPut << il2cpp_class_get_name(return_class) << " " << method_name
127 | << "(";
128 | if(method->methodPointer){
129 | method_info_outPut << ":" << method_name << "\n";
130 | }
131 | auto param_count = il2cpp_method_get_param_count(method);
132 | for (int i = 0; i < param_count; ++i) {
133 | auto param = il2cpp_method_get_param(method, i);
134 | auto attrs = param->attrs;
135 | if (_il2cpp_type_is_byref(param)) {
136 | if (attrs & PARAM_ATTRIBUTE_OUT && !(attrs & PARAM_ATTRIBUTE_IN)) {
137 | outPut << "out ";
138 | } else if (attrs & PARAM_ATTRIBUTE_IN && !(attrs & PARAM_ATTRIBUTE_OUT)) {
139 | outPut << "in ";
140 | } else {
141 | outPut << "ref ";
142 | }
143 | } else {
144 | if (attrs & PARAM_ATTRIBUTE_IN) {
145 | outPut << "[In] ";
146 | }
147 | if (attrs & PARAM_ATTRIBUTE_OUT) {
148 | outPut << "[Out] ";
149 | }
150 | }
151 | auto parameter_class = il2cpp_class_from_type(param);
152 | outPut << il2cpp_class_get_name(parameter_class)<< " ";
153 | auto param_name = il2cpp_method_get_param_name(method, i);
154 | if(param_name){
155 | outPut << param_name;
156 | } else{
157 | outPut << "null_param_name";
158 | }
159 |
160 | outPut << ", ";
161 | }
162 | if (param_count > 0) {
163 | outPut.seekp(-2, outPut.cur);
164 | }
165 | outPut << ") { }\n";
166 | //TODO GenericInstMethod
167 | }
168 | return outPut.str();
169 | }
170 |
171 | std::string dump_property(Il2CppClass *klass) {
172 | std::stringstream outPut;
173 | outPut << "\n\t// Properties\n";
174 | void *iter = nullptr;
175 | while (auto prop_const = il2cpp_class_get_properties(klass, &iter)) {
176 | //TODO attribute
177 | auto prop = const_cast(prop_const);
178 | auto get = il2cpp_property_get_get_method(prop);
179 | auto set = il2cpp_property_get_set_method(prop);
180 | auto prop_name = il2cpp_property_get_name(prop);
181 | outPut << "\t";
182 | Il2CppClass *prop_class = nullptr;
183 | uint32_t iflags = 0;
184 | if (get) {
185 | outPut << get_method_modifier(il2cpp_method_get_flags(get, &iflags));
186 | prop_class = il2cpp_class_from_type(il2cpp_method_get_return_type(get));
187 | } else if (set) {
188 | outPut << get_method_modifier(il2cpp_method_get_flags(set, &iflags));
189 | auto param = il2cpp_method_get_param(set, 0);
190 | prop_class = il2cpp_class_from_type(param);
191 | }
192 | if (prop_class) {
193 | outPut << il2cpp_class_get_name(prop_class) << " " << prop_name << " { ";
194 | if (get) {
195 | outPut << "get; ";
196 | }
197 | if (set) {
198 | outPut << "set; ";
199 | }
200 | outPut << "}\n";
201 | } else {
202 | if (prop_name) {
203 | outPut << " // unknown property " << prop_name;
204 | }
205 | }
206 | }
207 | return outPut.str();
208 | }
209 |
210 | std::string dump_field(Il2CppClass *klass) {
211 | std::stringstream outPut;
212 | outPut << "\n\t// Fields\n";
213 | auto is_enum = il2cpp_class_is_enum(klass);
214 | void *iter = nullptr;
215 | while (auto field = il2cpp_class_get_fields(klass, &iter)) {
216 | //TODO attribute
217 | outPut << "\t";
218 | auto attrs = il2cpp_field_get_flags(field);
219 | auto access = attrs & FIELD_ATTRIBUTE_FIELD_ACCESS_MASK;
220 | switch (access) {
221 | case FIELD_ATTRIBUTE_PRIVATE:
222 | outPut << "private ";
223 | break;
224 | case FIELD_ATTRIBUTE_PUBLIC:
225 | outPut << "public ";
226 | break;
227 | case FIELD_ATTRIBUTE_FAMILY:
228 | outPut << "protected ";
229 | break;
230 | case FIELD_ATTRIBUTE_ASSEMBLY:
231 | case FIELD_ATTRIBUTE_FAM_AND_ASSEM:
232 | outPut << "internal ";
233 | break;
234 | case FIELD_ATTRIBUTE_FAM_OR_ASSEM:
235 | outPut << "protected internal ";
236 | break;
237 | }
238 | if (attrs & FIELD_ATTRIBUTE_LITERAL) {
239 | outPut << "const ";
240 | } else {
241 | if (attrs & FIELD_ATTRIBUTE_STATIC) {
242 | outPut << "static ";
243 | }
244 | if (attrs & FIELD_ATTRIBUTE_INIT_ONLY) {
245 | outPut << "readonly ";
246 | }
247 | }
248 | auto field_type = il2cpp_field_get_type(field);
249 | auto field_class = il2cpp_class_from_type(field_type);
250 | outPut << il2cpp_class_get_name(field_class) << " " << il2cpp_field_get_name(field);
251 | //TODO 获取构造函数初始化后的字段值
252 | if (attrs & FIELD_ATTRIBUTE_LITERAL && is_enum) {
253 | uint64_t val = 0;
254 | il2cpp_field_static_get_value(field, &val);
255 | outPut << " = " << std::dec << val;
256 | }
257 | outPut << "; // 0x" << std::hex << il2cpp_field_get_offset(field) << "\n";
258 | }
259 | return outPut.str();
260 | }
261 |
262 | std::string dump_type_info(Il2CppMetadataType type_info) {
263 | std::stringstream outPut;
264 |
265 | auto flags = type_info.flags;
266 | if (flags & TYPE_ATTRIBUTE_SERIALIZABLE) {
267 | outPut << "[Serializable]\n";
268 | }
269 | auto klass = reinterpret_cast(type_info.typeInfoAddress);
270 | // //TODO attribute
271 | auto is_valuetype = il2cpp_class_is_valuetype(klass);
272 | auto is_enum = il2cpp_class_is_enum(klass);
273 | // auto visibility = flags & TYPE_ATTRIBUTE_VISIBILITY_MASK;
274 | // switch (visibility) {
275 | // case TYPE_ATTRIBUTE_PUBLIC:
276 | // case TYPE_ATTRIBUTE_NESTED_PUBLIC:
277 | // outPut << "public ";
278 | // break;
279 | // case TYPE_ATTRIBUTE_NOT_PUBLIC:
280 | // case TYPE_ATTRIBUTE_NESTED_FAM_AND_ASSEM:
281 | // case TYPE_ATTRIBUTE_NESTED_ASSEMBLY:
282 | // outPut << "internal ";
283 | // break;
284 | // case TYPE_ATTRIBUTE_NESTED_PRIVATE:
285 | // outPut << "private ";
286 | // break;
287 | // case TYPE_ATTRIBUTE_NESTED_FAMILY:
288 | // outPut << "protected ";
289 | // break;
290 | // case TYPE_ATTRIBUTE_NESTED_FAM_OR_ASSEM:
291 | // outPut << "protected internal ";
292 | // break;
293 | // }
294 | if (flags & TYPE_ATTRIBUTE_ABSTRACT && flags & TYPE_ATTRIBUTE_SEALED) {
295 | outPut << "static ";
296 | } else if (!(flags & TYPE_ATTRIBUTE_INTERFACE) && flags & TYPE_ATTRIBUTE_ABSTRACT) {
297 | outPut << "abstract ";
298 | } else if (!is_valuetype && !is_enum && flags & TYPE_ATTRIBUTE_SEALED) {
299 | outPut << "sealed ";
300 | }
301 | if (flags & TYPE_ATTRIBUTE_INTERFACE) {
302 | outPut << "interface ";
303 | } else if (is_enum) {
304 | outPut << "enum ";
305 | } else if (is_valuetype) {
306 | outPut << "struct ";
307 | } else {
308 | outPut << "class ";
309 | }
310 | outPut << type_info.name; //TODO genericContainerIndex
311 | std::vector extends;
312 | // auto parent = il2cpp_class_get_parent(klass);
313 | // if (!is_valuetype && !is_enum && parent) {
314 | // auto parent_type = il2cpp_class_get_type(parent);
315 | // if (parent_type->type != IL2CPP_TYPE_OBJECT) {
316 | // extends.emplace_back(il2cpp_class_get_name(parent));
317 | // }
318 | // }
319 | // void *iter = nullptr;
320 | // while (auto itf = il2cpp_class_get_interfaces(klass, &iter)) {
321 | // extends.emplace_back(il2cpp_class_get_name(itf));
322 | // }
323 | if (!extends.empty()) {
324 | outPut << " : " << extends[0];
325 | for (int i = 1; i < extends.size(); ++i) {
326 | outPut << ", " << extends[i];
327 | }
328 | }
329 | outPut << "\n{";
330 | outPut << dump_field(klass);
331 | outPut << dump_property(klass);
332 | outPut << dump_method(klass);
333 | //TODO EventInfo
334 | outPut << "}\n\n";
335 | return outPut.str();
336 | }
337 |
338 |
339 | void test_il2cpp_api(Il2CppMetadataType type_info){
340 | auto klass = reinterpret_cast(type_info.typeInfoAddress);
341 | LOGD("checking il2cpp_class_is_valuetype...");
342 | il2cpp_class_is_valuetype(klass);
343 | LOGD("checking il2cpp_class_is_enum...");
344 | il2cpp_class_is_enum(klass);
345 | LOGD("checking il2cpp_class_get_fields...");
346 | void *iter = nullptr;
347 | auto field = il2cpp_class_get_fields(klass, &iter);
348 | LOGD("checking il2cpp_field_get_flags...");
349 | il2cpp_field_get_flags(field);
350 | LOGD("checking il2cpp_field_get_type...");
351 | auto field_type = il2cpp_field_get_type(field);
352 | LOGD("checking il2cpp_class_from_type...");
353 | auto field_class = il2cpp_class_from_type(field_type);
354 | LOGD("checking il2cpp_class_get_name...");
355 | il2cpp_class_get_name(field_class);
356 | LOGD("checking il2cpp_field_get_name...");
357 | il2cpp_field_get_name(field);
358 | LOGD("checking il2cpp_field_static_get_value...");
359 | uint64_t val = 0;
360 | il2cpp_field_static_get_value(field, &val);
361 | LOGD("checking il2cpp_field_get_offset...");
362 | il2cpp_field_get_offset(field);
363 |
364 | LOGD("checking il2cpp_class_get_properties...");
365 | iter = nullptr;
366 | auto prop_const = il2cpp_class_get_properties(klass, &iter);
367 |
368 | auto prop = const_cast(prop_const);
369 | LOGD("checking il2cpp_property_get_get_method...");
370 | auto get = il2cpp_property_get_get_method(prop);
371 | LOGD("checking il2cpp_property_get_set_method...");
372 | il2cpp_property_get_set_method(prop);
373 | LOGD("checking il2cpp_property_get_name...");
374 | auto prop_name = il2cpp_property_get_name(prop);
375 |
376 | uint32_t iflags = 0;
377 | LOGD("checking il2cpp_method_get_flags...");
378 | auto method_flag = il2cpp_method_get_flags(get, &iflags);
379 | LOGD("checking get_method_modifier...");
380 | get_method_modifier(method_flag);
381 | LOGD("checking il2cpp_method_get_return_type...");
382 | auto return_type = il2cpp_method_get_return_type(get);
383 | LOGD("checking il2cpp_type_is_byref...");
384 | il2cpp_type_is_byref(return_type);
385 |
386 | iter = nullptr;
387 | LOGD("checking il2cpp_class_get_methods...");
388 | auto method = il2cpp_class_get_methods(klass, &iter);
389 | LOGD("checking il2cpp_method_get_name...");
390 | il2cpp_method_get_name(method);
391 | LOGD("checking il2cpp_method_get_param_count...");
392 | auto count = il2cpp_method_get_param_count(method);
393 | if(count!=0){
394 | LOGD("checking il2cpp_method_get_param...");
395 | il2cpp_method_get_param(method, 0);
396 | LOGD("checking il2cpp_method_get_param_name...");
397 | il2cpp_method_get_param_name(method, 0);
398 | } else{
399 | LOGE("no test il2cpp_method_get_param and il2cpp_method_get_param_name");
400 | }
401 |
402 | LOGD("all test success.");
403 |
404 | }
405 |
406 | void il2cpp_api_init(void *handle) {
407 | LOGI("il2cpp_handle: %p", handle);
408 | init_il2cpp_api(handle);
409 | if (il2cpp_capture_memory_snapshot) {
410 | Dl_info dlInfo;
411 | if (dladdr((void *) il2cpp_capture_memory_snapshot, &dlInfo)) {
412 | il2cpp_base = reinterpret_cast(dlInfo.dli_fbase);
413 | }
414 | LOGI("il2cpp_base: %" PRIx64"", il2cpp_base);
415 | } else {
416 | LOGE("Failed to initialize il2cpp api.");
417 | return;
418 | }
419 | while (!il2cpp_is_vm_thread(nullptr)) {
420 | LOGI("Waiting for il2cpp_init...");
421 | sleep(1);
422 | }
423 | // auto domain = il2cpp_domain_get();
424 | // il2cpp_thread_attach(domain);
425 | }
426 |
427 | void il2cpp_dump(const char *outDir) {
428 | LOGI("dumping...");
429 | std::vector outPuts;
430 | if (il2cpp_capture_memory_snapshot && il2cpp_free_captured_memory_snapshot) {
431 | auto memorySnapshot = il2cpp_capture_memory_snapshot();
432 | auto all_type_infos_count = memorySnapshot->metadata.typeCount;
433 | auto all_type_infos = memorySnapshot->metadata.types;
434 | LOGD("all_typeCount:%d",all_type_infos_count);
435 |
436 | for (int i = 0; i < all_type_infos_count; ++i) {
437 | if(strcmp(all_type_infos[i].name,"System.String")==0){
438 | LOGD("test start.");
439 | test_il2cpp_api(all_type_infos[i]);
440 | break;
441 | }
442 | }
443 |
444 | for (int k = 0; k < all_type_infos_count; ++k) {
445 | auto tmp_type_info = all_type_infos[k];
446 | auto outPut = std::string(tmp_type_info.assemblyName)+".dll\n"+ dump_type_info(tmp_type_info);
447 | outPuts.push_back(outPut);
448 | }
449 | il2cpp_free_captured_memory_snapshot(memorySnapshot);
450 | } else {
451 | LOGE("can not find il2cpp_capture_memory_snapshot!!!");
452 | }
453 |
454 | LOGI("write dump file");
455 | auto outPath = std::string(outDir).append("/files/test.cs");
456 | std::ofstream outStream(outPath);
457 | auto outPath2 = std::string(outDir).append("/files/test_method_info.txt");
458 | std::ofstream outStream2(outPath2);
459 |
460 | if(outStream.is_open()){
461 | auto count = outPuts.size();
462 | for (int i = 0; i < count; ++i) {
463 | outStream << outPuts[i];
464 | }
465 | } else
466 | LOGE("can not open file:%s",outPath.c_str());
467 |
468 | outStream.close();
469 | if (outStream2.is_open()){
470 | outStream2 << method_info_outPut.str();
471 | } else
472 | LOGE("can not open file:%s",outPath2.c_str());
473 | method_info_outPut.flush();
474 | method_info_outPut.clear();
475 | outStream2.close();
476 | LOGI("dump done!");
477 | }
--------------------------------------------------------------------------------
/app/src/main/cpp/il2cpp_dump.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Perfare on 2020/7/4.
3 | //
4 |
5 | #ifndef ZYGISK_IL2CPPDUMPER_IL2CPP_DUMP_H
6 | #define ZYGISK_IL2CPPDUMPER_IL2CPP_DUMP_H
7 |
8 |
9 | #include
10 |
11 | struct Il2CppMetadataField
12 | {
13 | uint32_t offset;
14 | uint32_t typeIndex;
15 | const char* name;
16 | bool isStatic;
17 | };
18 |
19 | enum Il2CppMetadataTypeFlags
20 | {
21 | kNone = 0,
22 | kValueType = 1 << 0,
23 | kArray = 1 << 1,
24 | kArrayRankMask = 0xFFFF0000
25 | };
26 |
27 | struct Il2CppMetadataType
28 | {
29 | Il2CppMetadataTypeFlags flags; // If it's an array, rank is encoded in the upper 2 bytes
30 | Il2CppMetadataField* fields;
31 | uint32_t fieldCount;
32 | uint32_t staticsSize;
33 | uint8_t* statics;
34 | uint32_t baseOrElementTypeIndex;
35 | char* name;
36 | const char* assemblyName;
37 | uint64_t typeInfoAddress;
38 | uint32_t size;
39 | };
40 |
41 | struct Il2CppMetadataSnapshot
42 | {
43 | uint32_t typeCount;
44 | Il2CppMetadataType* types;
45 | };
46 |
47 | struct Il2CppManagedMemorySection
48 | {
49 | uint64_t sectionStartAddress;
50 | uint32_t sectionSize;
51 | uint8_t* sectionBytes;
52 | };
53 |
54 | struct Il2CppManagedHeap
55 | {
56 | uint32_t sectionCount;
57 | Il2CppManagedMemorySection* sections;
58 | };
59 |
60 | struct Il2CppStacks
61 | {
62 | uint32_t stackCount;
63 | Il2CppManagedMemorySection* stacks;
64 | };
65 |
66 | struct NativeObject
67 | {
68 | uint32_t gcHandleIndex;
69 | uint32_t size;
70 | uint32_t instanceId;
71 | uint32_t classId;
72 | uint32_t referencedNativeObjectIndicesCount;
73 | uint32_t* referencedNativeObjectIndices;
74 | };
75 |
76 | struct Il2CppGCHandles
77 | {
78 | uint32_t trackedObjectCount;
79 | uint64_t* pointersToObjects;
80 | };
81 |
82 | struct Il2CppRuntimeInformation
83 | {
84 | uint32_t pointerSize;
85 | uint32_t objectHeaderSize;
86 | uint32_t arrayHeaderSize;
87 | uint32_t arrayBoundsOffsetInHeader;
88 | uint32_t arraySizeOffsetInHeader;
89 | uint32_t allocationGranularity;
90 | };
91 |
92 | struct Il2CppManagedMemorySnapshot
93 | {
94 | Il2CppManagedHeap heap;
95 | Il2CppStacks stacks;
96 | Il2CppMetadataSnapshot metadata;
97 | Il2CppGCHandles gcHandles;
98 | Il2CppRuntimeInformation runtimeInformation;
99 | void* additionalUserInformation;
100 | };
101 |
102 |
103 |
104 | void il2cpp_api_init(void *handle);
105 |
106 | void il2cpp_dump(const char *outDir);
107 |
108 | #endif //ZYGISK_IL2CPPDUMPER_IL2CPP_DUMP_H
109 |
--------------------------------------------------------------------------------
/app/src/main/cpp/log.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by Perfare on 2020/7/4.
3 | //
4 |
5 | #ifndef ZYGISK_IL2CPPDUMPER_LOG_H
6 | #define ZYGISK_IL2CPPDUMPER_LOG_H
7 |
8 | #include
9 |
10 | #define LOG_TAG "Perfare"
11 | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
12 | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
13 | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
14 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
15 |
16 | #endif //ZYGISK_IL2CPPDUMPER_LOG_H
17 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/include/xdl.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2020-10-04.
23 |
24 | //
25 | // xDL version: 1.2.1
26 | //
27 | // xDL is an enhanced implementation of the Android DL series functions.
28 | // For more information, documentation, and the latest version please check:
29 | // https://github.com/hexhacking/xDL
30 | //
31 |
32 | #ifndef IO_HEXHACKING_XDL
33 | #define IO_HEXHACKING_XDL
34 |
35 | #include
36 | #include
37 | #include
38 |
39 | #ifdef __cplusplus
40 | extern "C" {
41 | #endif
42 |
43 | typedef struct {
44 | // same as Dl_info:
45 | const char *dli_fname; // Pathname of shared object that contains address.
46 | void *dli_fbase; // Address at which shared object is loaded.
47 | const char *dli_sname; // Name of nearest symbol with address lower than addr.
48 | void *dli_saddr; // Exact address of symbol named in dli_sname.
49 | // added by xDL:
50 | size_t dli_ssize; // Symbol size of nearest symbol with address lower than addr.
51 | const ElfW(Phdr) *dlpi_phdr; // Pointer to array of ELF program headers for this object.
52 | size_t dlpi_phnum; // Number of items in dlpi_phdr.
53 | } xdl_info_t;
54 |
55 | //
56 | // Default value for flags in both xdl_open() and xdl_iterate_phdr().
57 | //
58 | #define XDL_DEFAULT 0x00
59 |
60 | //
61 | // Enhanced dlopen() / dlclose() / dlsym().
62 | //
63 | #define XDL_TRY_FORCE_LOAD 0x01
64 | #define XDL_ALWAYS_FORCE_LOAD 0x02
65 | void *xdl_open(const char *filename, int flags);
66 | void *xdl_close(void *handle);
67 | void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size);
68 | void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size);
69 |
70 | //
71 | // Enhanced dladdr().
72 | //
73 | int xdl_addr(void *addr, xdl_info_t *info, void **cache);
74 | void xdl_addr_clean(void **cache);
75 |
76 | //
77 | // Enhanced dl_iterate_phdr().
78 | //
79 | #define XDL_FULL_PATHNAME 0x01
80 | int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags);
81 |
82 | //
83 | // Custom dlinfo().
84 | //
85 | #define XDL_DI_DLINFO 1 // type of info: xdl_info_t
86 | int xdl_info(void *handle, int request, void *info);
87 |
88 | #ifdef __cplusplus
89 | }
90 | #endif
91 |
92 | #endif
93 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2020-10-04.
23 |
24 | #include "xdl.h"
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 | #include
39 | #include
40 | #include
41 | #include
42 | #include
43 |
44 | #include "xdl_iterate.h"
45 | #include "xdl_linker.h"
46 | #include "xdl_lzma.h"
47 | #include "xdl_util.h"
48 |
49 | #ifndef __LP64__
50 | #define XDL_LIB_PATH "/system/lib"
51 | #else
52 | #define XDL_LIB_PATH "/system/lib64"
53 | #endif
54 |
55 | #define XDL_DYNSYM_IS_EXPORT_SYM(shndx) (SHN_UNDEF != (shndx))
56 | #define XDL_SYMTAB_IS_EXPORT_SYM(shndx) \
57 | (SHN_UNDEF != (shndx) && !((shndx) >= SHN_LORESERVE && (shndx) <= SHN_HIRESERVE))
58 |
59 | extern __attribute((weak)) unsigned long int getauxval(unsigned long int);
60 |
61 | #pragma clang diagnostic push
62 | #pragma clang diagnostic ignored "-Wpadded"
63 |
64 | typedef struct xdl {
65 | char *pathname;
66 | uintptr_t load_bias;
67 | const ElfW(Phdr) *dlpi_phdr;
68 | ElfW(Half) dlpi_phnum;
69 |
70 | struct xdl *next; // to next xdl obj for cache in xdl_addr()
71 | void *linker_handle; // hold handle returned by xdl_linker_load()
72 |
73 | //
74 | // (1) for searching symbols from .dynsym
75 | //
76 |
77 | bool dynsym_try_load;
78 | ElfW(Sym) *dynsym; // .dynsym
79 | const char *dynstr; // .dynstr
80 |
81 | // .hash (SYSV hash for .dynstr)
82 | struct {
83 | const uint32_t *buckets;
84 | uint32_t buckets_cnt;
85 | const uint32_t *chains;
86 | uint32_t chains_cnt;
87 | } sysv_hash;
88 |
89 | // .gnu.hash (GNU hash for .dynstr)
90 | struct {
91 | const uint32_t *buckets;
92 | uint32_t buckets_cnt;
93 | const uint32_t *chains;
94 | uint32_t symoffset;
95 | const ElfW(Addr) *bloom;
96 | uint32_t bloom_cnt;
97 | uint32_t bloom_shift;
98 | } gnu_hash;
99 |
100 | //
101 | // (2) for searching symbols from .symtab
102 | //
103 |
104 | bool symtab_try_load;
105 | uintptr_t base;
106 |
107 | ElfW(Sym) *symtab; // .symtab
108 | size_t symtab_cnt;
109 | char *strtab; // .strtab
110 | size_t strtab_sz;
111 | } xdl_t;
112 |
113 | #pragma clang diagnostic pop
114 |
115 | // load from memory
116 | static int xdl_dynsym_load(xdl_t *self) {
117 | // find the dynamic segment
118 | ElfW(Dyn) *dynamic = NULL;
119 | for (size_t i = 0; i < self->dlpi_phnum; i++) {
120 | const ElfW(Phdr) *phdr = &(self->dlpi_phdr[i]);
121 | if (PT_DYNAMIC == phdr->p_type) {
122 | dynamic = (ElfW(Dyn) *)(self->load_bias + phdr->p_vaddr);
123 | break;
124 | }
125 | }
126 | if (NULL == dynamic) return -1;
127 |
128 | // iterate the dynamic segment
129 | for (ElfW(Dyn) *entry = dynamic; entry && entry->d_tag != DT_NULL; entry++) {
130 | switch (entry->d_tag) {
131 | case DT_SYMTAB: //.dynsym
132 | self->dynsym = (ElfW(Sym) *)(self->load_bias + entry->d_un.d_ptr);
133 | break;
134 | case DT_STRTAB: //.dynstr
135 | self->dynstr = (const char *)(self->load_bias + entry->d_un.d_ptr);
136 | break;
137 | case DT_HASH: //.hash
138 | self->sysv_hash.buckets_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[0];
139 | self->sysv_hash.chains_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[1];
140 | self->sysv_hash.buckets = &(((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[2]);
141 | self->sysv_hash.chains = &(self->sysv_hash.buckets[self->sysv_hash.buckets_cnt]);
142 | break;
143 | case DT_GNU_HASH: //.gnu.hash
144 | self->gnu_hash.buckets_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[0];
145 | self->gnu_hash.symoffset = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[1];
146 | self->gnu_hash.bloom_cnt = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[2];
147 | self->gnu_hash.bloom_shift = ((const uint32_t *)(self->load_bias + entry->d_un.d_ptr))[3];
148 | self->gnu_hash.bloom = (const ElfW(Addr) *)(self->load_bias + entry->d_un.d_ptr + 16);
149 | self->gnu_hash.buckets = (const uint32_t *)(&(self->gnu_hash.bloom[self->gnu_hash.bloom_cnt]));
150 | self->gnu_hash.chains = (const uint32_t *)(&(self->gnu_hash.buckets[self->gnu_hash.buckets_cnt]));
151 | break;
152 | default:
153 | break;
154 | }
155 | }
156 |
157 | if (NULL == self->dynsym || NULL == self->dynstr ||
158 | (0 == self->sysv_hash.buckets_cnt && 0 == self->gnu_hash.buckets_cnt)) {
159 | self->dynsym = NULL;
160 | self->dynstr = NULL;
161 | self->sysv_hash.buckets_cnt = 0;
162 | self->gnu_hash.buckets_cnt = 0;
163 | return -1;
164 | }
165 |
166 | return 0;
167 | }
168 |
169 | static void *xdl_read_file_to_heap(int file_fd, size_t file_sz, size_t data_offset, size_t data_len) {
170 | if (0 == data_len) return NULL;
171 | if (data_offset >= file_sz) return NULL;
172 | if (data_offset + data_len > file_sz) return NULL;
173 |
174 | if (data_offset != (size_t)lseek(file_fd, (off_t)data_offset, SEEK_SET)) return NULL;
175 |
176 | void *data = malloc(data_len);
177 | if (NULL == data) return NULL;
178 |
179 | #pragma clang diagnostic push
180 | #pragma clang diagnostic ignored "-Wgnu-statement-expression"
181 | if ((ssize_t)data_len != XDL_UTIL_TEMP_FAILURE_RETRY(read(file_fd, data, data_len)))
182 | #pragma clang diagnostic pop
183 | {
184 | free(data);
185 | return NULL;
186 | }
187 |
188 | return data;
189 | }
190 |
191 | static void *xdl_read_file_to_heap_by_section(int file_fd, size_t file_sz, ElfW(Shdr) *shdr) {
192 | return xdl_read_file_to_heap(file_fd, file_sz, (size_t)shdr->sh_offset, shdr->sh_size);
193 | }
194 |
195 | static void *xdl_read_memory_to_heap(void *mem, size_t mem_sz, size_t data_offset, size_t data_len) {
196 | if (0 == data_len) return NULL;
197 | if (data_offset >= mem_sz) return NULL;
198 | if (data_offset + data_len > mem_sz) return NULL;
199 |
200 | void *data = malloc(data_len);
201 | if (NULL == data) return NULL;
202 |
203 | memcpy(data, (void *)((uintptr_t)mem + data_offset), data_len);
204 | return data;
205 | }
206 |
207 | static void *xdl_read_memory_to_heap_by_section(void *mem, size_t mem_sz, ElfW(Shdr) *shdr) {
208 | return xdl_read_memory_to_heap(mem, mem_sz, (size_t)shdr->sh_offset, shdr->sh_size);
209 | }
210 |
211 | static void *xdl_get_memory(void *mem, size_t mem_sz, size_t data_offset, size_t data_len) {
212 | if (0 == data_len) return NULL;
213 | if (data_offset >= mem_sz) return NULL;
214 | if (data_offset + data_len > mem_sz) return NULL;
215 |
216 | return (void *)((uintptr_t)mem + data_offset);
217 | }
218 |
219 | static void *xdl_get_memory_by_section(void *mem, size_t mem_sz, ElfW(Shdr) *shdr) {
220 | return xdl_get_memory(mem, mem_sz, (size_t)shdr->sh_offset, shdr->sh_size);
221 | }
222 |
223 | // load from disk and memory
224 | static int xdl_symtab_load_from_debugdata(xdl_t *self, int file_fd, size_t file_sz,
225 | ElfW(Shdr) *shdr_debugdata) {
226 | void *debugdata = NULL;
227 | ElfW(Shdr) *shdrs = NULL;
228 | int r = -1;
229 |
230 | // get zipped .gnu_debugdata
231 | uint8_t *debugdata_zip = (uint8_t *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr_debugdata);
232 | if (NULL == debugdata_zip) return -1;
233 |
234 | // get unzipped .gnu_debugdata
235 | size_t debugdata_sz;
236 | if (0 != xdl_lzma_decompress(debugdata_zip, shdr_debugdata->sh_size, (uint8_t **)&debugdata, &debugdata_sz))
237 | goto end;
238 |
239 | // get ELF header
240 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)debugdata;
241 | if (0 == ehdr->e_shnum || ehdr->e_shentsize != sizeof(ElfW(Shdr))) goto end;
242 |
243 | // get section headers
244 | shdrs = (ElfW(Shdr) *)xdl_read_memory_to_heap(debugdata, debugdata_sz, (size_t)ehdr->e_shoff,
245 | ehdr->e_shentsize * ehdr->e_shnum);
246 | if (NULL == shdrs) goto end;
247 |
248 | // get .shstrtab
249 | if (SHN_UNDEF == ehdr->e_shstrndx || ehdr->e_shstrndx >= ehdr->e_shnum) goto end;
250 | char *shstrtab = (char *)xdl_get_memory_by_section(debugdata, debugdata_sz, shdrs + ehdr->e_shstrndx);
251 | if (NULL == shstrtab) goto end;
252 |
253 | // find .symtab & .strtab
254 | for (ElfW(Shdr) *shdr = shdrs; shdr < shdrs + ehdr->e_shnum; shdr++) {
255 | char *shdr_name = shstrtab + shdr->sh_name;
256 |
257 | if (SHT_SYMTAB == shdr->sh_type && 0 == strcmp(".symtab", shdr_name)) {
258 | // get & check associated .strtab section
259 | if (shdr->sh_link >= ehdr->e_shnum) continue;
260 | ElfW(Shdr) *shdr_strtab = shdrs + shdr->sh_link;
261 | if (SHT_STRTAB != shdr_strtab->sh_type) continue;
262 |
263 | // get .symtab & .strtab
264 | ElfW(Sym) *symtab = (ElfW(Sym) *)xdl_read_memory_to_heap_by_section(debugdata, debugdata_sz, shdr);
265 | if (NULL == symtab) continue;
266 | char *strtab = (char *)xdl_read_memory_to_heap_by_section(debugdata, debugdata_sz, shdr_strtab);
267 | if (NULL == strtab) {
268 | free(symtab);
269 | continue;
270 | }
271 |
272 | // OK
273 | self->symtab = symtab;
274 | self->symtab_cnt = shdr->sh_size / shdr->sh_entsize;
275 | self->strtab = strtab;
276 | self->strtab_sz = shdr_strtab->sh_size;
277 | r = 0;
278 | break;
279 | }
280 | }
281 |
282 | end:
283 | free(debugdata_zip);
284 | if (NULL != debugdata) free(debugdata);
285 | if (NULL != shdrs) free(shdrs);
286 | return r;
287 | }
288 |
289 | // load from disk and memory
290 | static int xdl_symtab_load(xdl_t *self) {
291 | if ('[' == self->pathname[0]) return -1;
292 |
293 | int r = -1;
294 | ElfW(Shdr) *shdrs = NULL;
295 | char *shstrtab = NULL;
296 |
297 | // get base address
298 | uintptr_t vaddr_min = UINTPTR_MAX;
299 | for (size_t i = 0; i < self->dlpi_phnum; i++) {
300 | const ElfW(Phdr) *phdr = &(self->dlpi_phdr[i]);
301 | if (PT_LOAD == phdr->p_type) {
302 | if (vaddr_min > phdr->p_vaddr) vaddr_min = phdr->p_vaddr;
303 | }
304 | }
305 | if (UINTPTR_MAX == vaddr_min) return -1;
306 | self->base = self->load_bias + vaddr_min;
307 |
308 | // open file
309 | int flags = O_RDONLY | O_CLOEXEC;
310 | int file_fd;
311 | if ('/' == self->pathname[0]) {
312 | file_fd = open(self->pathname, flags);
313 | } else {
314 | char full_pathname[1024];
315 | // try the fast method
316 | snprintf(full_pathname, sizeof(full_pathname), "%s/%s", XDL_LIB_PATH, self->pathname);
317 | file_fd = open(full_pathname, flags);
318 | if (file_fd < 0) {
319 | // try the slow method
320 | if (0 != xdl_iterate_get_full_pathname(self->base, full_pathname, sizeof(full_pathname))) return -1;
321 | file_fd = open(full_pathname, flags);
322 | }
323 | }
324 | if (file_fd < 0) return -1;
325 | struct stat st;
326 | if (0 != fstat(file_fd, &st)) goto end;
327 | size_t file_sz = (size_t)st.st_size;
328 |
329 | // get ELF header
330 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)self->base;
331 | if (0 == ehdr->e_shnum || ehdr->e_shentsize != sizeof(ElfW(Shdr))) goto end;
332 |
333 | // get section headers
334 | shdrs = (ElfW(Shdr) *)xdl_read_file_to_heap(file_fd, file_sz, (size_t)ehdr->e_shoff,
335 | ehdr->e_shentsize * ehdr->e_shnum);
336 | if (NULL == shdrs) goto end;
337 |
338 | // get .shstrtab
339 | if (SHN_UNDEF == ehdr->e_shstrndx || ehdr->e_shstrndx >= ehdr->e_shnum) goto end;
340 | shstrtab = (char *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdrs + ehdr->e_shstrndx);
341 | if (NULL == shstrtab) goto end;
342 |
343 | // find .symtab & .strtab
344 | for (ElfW(Shdr) *shdr = shdrs; shdr < shdrs + ehdr->e_shnum; shdr++) {
345 | char *shdr_name = shstrtab + shdr->sh_name;
346 |
347 | if (SHT_SYMTAB == shdr->sh_type && 0 == strcmp(".symtab", shdr_name)) {
348 | // get & check associated .strtab section
349 | if (shdr->sh_link >= ehdr->e_shnum) continue;
350 | ElfW(Shdr) *shdr_strtab = shdrs + shdr->sh_link;
351 | if (SHT_STRTAB != shdr_strtab->sh_type) continue;
352 |
353 | // get .symtab & .strtab
354 | ElfW(Sym) *symtab = (ElfW(Sym) *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr);
355 | if (NULL == symtab) continue;
356 | char *strtab = (char *)xdl_read_file_to_heap_by_section(file_fd, file_sz, shdr_strtab);
357 | if (NULL == strtab) {
358 | free(symtab);
359 | continue;
360 | }
361 |
362 | // OK
363 | self->symtab = symtab;
364 | self->symtab_cnt = shdr->sh_size / shdr->sh_entsize;
365 | self->strtab = strtab;
366 | self->strtab_sz = shdr_strtab->sh_size;
367 | r = 0;
368 | break;
369 | } else if (SHT_PROGBITS == shdr->sh_type && 0 == strcmp(".gnu_debugdata", shdr_name)) {
370 | if (0 == xdl_symtab_load_from_debugdata(self, file_fd, file_sz, shdr)) {
371 | // OK
372 | r = 0;
373 | break;
374 | }
375 | }
376 | }
377 |
378 | end:
379 | close(file_fd);
380 | if (NULL != shdrs) free(shdrs);
381 | if (NULL != shstrtab) free(shstrtab);
382 | return r;
383 | }
384 |
385 | static xdl_t *xdl_find_from_auxv(unsigned long type, const char *pathname) {
386 | if (NULL == getauxval) return NULL;
387 |
388 | uintptr_t val = (uintptr_t)getauxval(type);
389 | if (0 == val) return NULL;
390 |
391 | // get base
392 | uintptr_t base = (AT_PHDR == type ? (val & (~0xffful)) : val);
393 | if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) return NULL;
394 |
395 | // ELF info
396 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base;
397 | const ElfW(Phdr) *dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff);
398 | ElfW(Half) dlpi_phnum = ehdr->e_phnum;
399 |
400 | // get bias
401 | uintptr_t min_vaddr = UINTPTR_MAX;
402 | for (size_t i = 0; i < dlpi_phnum; i++) {
403 | const ElfW(Phdr) *phdr = &(dlpi_phdr[i]);
404 | if (PT_LOAD == phdr->p_type) {
405 | if (min_vaddr > phdr->p_vaddr) min_vaddr = phdr->p_vaddr;
406 | }
407 | }
408 | if (UINTPTR_MAX == min_vaddr || base < min_vaddr) return NULL;
409 | uintptr_t load_bias = base - min_vaddr;
410 |
411 | // create xDL object
412 | xdl_t *self;
413 | if (NULL == (self = calloc(1, sizeof(xdl_t)))) return NULL;
414 | if (NULL == (self->pathname = strdup(pathname))) {
415 | free(self);
416 | return NULL;
417 | }
418 | self->load_bias = load_bias;
419 | self->dlpi_phdr = dlpi_phdr;
420 | self->dlpi_phnum = dlpi_phnum;
421 | self->dynsym_try_load = false;
422 | self->symtab_try_load = false;
423 | return self;
424 | }
425 |
426 | static int xdl_find_iterate_cb(struct dl_phdr_info *info, size_t size, void *arg) {
427 | (void)size;
428 |
429 | uintptr_t *pkg = (uintptr_t *)arg;
430 | xdl_t **self = (xdl_t **)*pkg++;
431 | const char *filename = (const char *)*pkg;
432 |
433 | // check load_bias
434 | if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0;
435 |
436 | // check pathname
437 | if ('[' == filename[0]) {
438 | if (0 != strcmp(info->dlpi_name, filename)) return 0;
439 | } else if ('/' == filename[0]) {
440 | if ('/' == info->dlpi_name[0]) {
441 | if (0 != strcmp(info->dlpi_name, filename)) return 0;
442 | } else {
443 | if (!xdl_util_ends_with(filename, info->dlpi_name)) return 0;
444 | }
445 | } else {
446 | if ('/' == info->dlpi_name[0]) {
447 | if (!xdl_util_ends_with(info->dlpi_name, filename)) return 0;
448 | } else {
449 | if (0 != strcmp(info->dlpi_name, filename)) return 0;
450 | }
451 | }
452 |
453 | // found the target ELF
454 | if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; // return failed
455 | if (NULL == ((*self)->pathname = strdup(info->dlpi_name))) {
456 | free(*self);
457 | *self = NULL;
458 | return 1; // return failed
459 | }
460 | (*self)->load_bias = info->dlpi_addr;
461 | (*self)->dlpi_phdr = info->dlpi_phdr;
462 | (*self)->dlpi_phnum = info->dlpi_phnum;
463 | (*self)->dynsym_try_load = false;
464 | (*self)->symtab_try_load = false;
465 | return 1; // return OK
466 | }
467 |
468 | static xdl_t *xdl_find(const char *filename) {
469 | // from auxv (linker, vDSO)
470 | xdl_t *self = NULL;
471 | if (xdl_util_ends_with(filename, XDL_UTIL_LINKER_BASENAME))
472 | self = xdl_find_from_auxv(AT_BASE, XDL_UTIL_LINKER_PATHNAME);
473 | else if (xdl_util_ends_with(filename, XDL_UTIL_VDSO_BASENAME))
474 | self = xdl_find_from_auxv(AT_SYSINFO_EHDR, XDL_UTIL_VDSO_BASENAME);
475 |
476 | // from auxv (app_process)
477 | const char *basename, *pathname;
478 | #if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__
479 | if (xdl_util_get_api_level() < __ANDROID_API_L__) {
480 | basename = XDL_UTIL_APP_PROCESS_BASENAME_K;
481 | pathname = XDL_UTIL_APP_PROCESS_PATHNAME_K;
482 | } else
483 | #endif
484 | {
485 | basename = XDL_UTIL_APP_PROCESS_BASENAME;
486 | pathname = XDL_UTIL_APP_PROCESS_PATHNAME;
487 | }
488 | if (xdl_util_ends_with(filename, basename)) self = xdl_find_from_auxv(AT_PHDR, pathname);
489 |
490 | if (NULL != self) return self;
491 |
492 | // from dl_iterate_phdr
493 | uintptr_t pkg[2] = {(uintptr_t)&self, (uintptr_t)filename};
494 | xdl_iterate_phdr(xdl_find_iterate_cb, pkg, XDL_DEFAULT);
495 | return self;
496 | }
497 |
498 | static void *xdl_open_always_force(const char *filename) {
499 | // always force dlopen()
500 | void *linker_handle = xdl_linker_load(filename);
501 | if (NULL == linker_handle) return NULL;
502 |
503 | // find
504 | xdl_t *self = xdl_find(filename);
505 | if (NULL == self)
506 | dlclose(linker_handle);
507 | else
508 | self->linker_handle = linker_handle;
509 |
510 | return (void *)self;
511 | }
512 |
513 | static void *xdl_open_try_force(const char *filename) {
514 | // find
515 | xdl_t *self = xdl_find(filename);
516 | if (NULL != self) return (void *)self;
517 |
518 | // try force dlopen()
519 | void *linker_handle = xdl_linker_load(filename);
520 | if (NULL == linker_handle) return NULL;
521 |
522 | // find again
523 | self = xdl_find(filename);
524 | if (NULL == self)
525 | dlclose(linker_handle);
526 | else
527 | self->linker_handle = linker_handle;
528 |
529 | return (void *)self;
530 | }
531 |
532 | void *xdl_open(const char *filename, int flags) {
533 | if (NULL == filename) return NULL;
534 |
535 | if (flags & XDL_ALWAYS_FORCE_LOAD)
536 | return xdl_open_always_force(filename);
537 | else if (flags & XDL_TRY_FORCE_LOAD)
538 | return xdl_open_try_force(filename);
539 | else
540 | return xdl_find(filename);
541 | }
542 |
543 | void *xdl_close(void *handle) {
544 | if (NULL == handle) return NULL;
545 |
546 | xdl_t *self = (xdl_t *)handle;
547 | if (NULL != self->pathname) free(self->pathname);
548 | if (NULL != self->symtab) free(self->symtab);
549 | if (NULL != self->strtab) free(self->strtab);
550 |
551 | void *linker_handle = self->linker_handle;
552 | free(self);
553 | return linker_handle;
554 | }
555 |
556 | static uint32_t xdl_sysv_hash(const uint8_t *name) {
557 | uint32_t h = 0, g;
558 |
559 | while (*name) {
560 | h = (h << 4) + *name++;
561 | g = h & 0xf0000000;
562 | h ^= g;
563 | h ^= g >> 24;
564 | }
565 | return h;
566 | }
567 |
568 | static uint32_t xdl_gnu_hash(const uint8_t *name) {
569 | uint32_t h = 5381;
570 |
571 | while (*name) {
572 | h += (h << 5) + *name++;
573 | }
574 | return h;
575 | }
576 |
577 | static ElfW(Sym) *xdl_dynsym_find_symbol_use_sysv_hash(xdl_t *self, const char *sym_name) {
578 | uint32_t hash = xdl_sysv_hash((const uint8_t *)sym_name);
579 |
580 | for (uint32_t i = self->sysv_hash.buckets[hash % self->sysv_hash.buckets_cnt]; 0 != i;
581 | i = self->sysv_hash.chains[i]) {
582 | ElfW(Sym) *sym = self->dynsym + i;
583 | if (0 != strcmp(self->dynstr + sym->st_name, sym_name)) continue;
584 | return sym;
585 | }
586 |
587 | return NULL;
588 | }
589 |
590 | static ElfW(Sym) *xdl_dynsym_find_symbol_use_gnu_hash(xdl_t *self, const char *sym_name) {
591 | uint32_t hash = xdl_gnu_hash((const uint8_t *)sym_name);
592 |
593 | static uint32_t elfclass_bits = sizeof(ElfW(Addr)) * 8;
594 | size_t word = self->gnu_hash.bloom[(hash / elfclass_bits) % self->gnu_hash.bloom_cnt];
595 | size_t mask = 0 | (size_t)1 << (hash % elfclass_bits) |
596 | (size_t)1 << ((hash >> self->gnu_hash.bloom_shift) % elfclass_bits);
597 |
598 | // if at least one bit is not set, this symbol is surely missing
599 | if ((word & mask) != mask) return NULL;
600 |
601 | // ignore STN_UNDEF
602 | uint32_t i = self->gnu_hash.buckets[hash % self->gnu_hash.buckets_cnt];
603 | if (i < self->gnu_hash.symoffset) return NULL;
604 |
605 | // loop through the chain
606 | while (1) {
607 | ElfW(Sym) *sym = self->dynsym + i;
608 | uint32_t sym_hash = self->gnu_hash.chains[i - self->gnu_hash.symoffset];
609 |
610 | if ((hash | (uint32_t)1) == (sym_hash | (uint32_t)1)) {
611 | if (0 == strcmp(self->dynstr + sym->st_name, sym_name)) {
612 | return sym;
613 | }
614 | }
615 |
616 | // chain ends with an element with the lowest bit set to 1
617 | if (sym_hash & (uint32_t)1) break;
618 |
619 | i++;
620 | }
621 |
622 | return NULL;
623 | }
624 |
625 | void *xdl_sym(void *handle, const char *symbol, size_t *symbol_size) {
626 | if (NULL == handle || NULL == symbol) return NULL;
627 | if (NULL != symbol_size) *symbol_size = 0;
628 |
629 | xdl_t *self = (xdl_t *)handle;
630 |
631 | // load .dynsym only once
632 | if (!self->dynsym_try_load) {
633 | self->dynsym_try_load = true;
634 | if (0 != xdl_dynsym_load(self)) return NULL;
635 | }
636 |
637 | // find symbol
638 | if (NULL == self->dynsym) return NULL;
639 | ElfW(Sym) *sym = NULL;
640 | if (self->gnu_hash.buckets_cnt > 0) {
641 | // use GNU hash (.gnu.hash -> .dynsym -> .dynstr), O(x) + O(1) + O(1)
642 | sym = xdl_dynsym_find_symbol_use_gnu_hash(self, symbol);
643 | }
644 | if (NULL == sym && self->sysv_hash.buckets_cnt > 0) {
645 | // use SYSV hash (.hash -> .dynsym -> .dynstr), O(x) + O(1) + O(1)
646 | sym = xdl_dynsym_find_symbol_use_sysv_hash(self, symbol);
647 | }
648 | if (NULL == sym || !XDL_DYNSYM_IS_EXPORT_SYM(sym->st_shndx)) return NULL;
649 |
650 | if (NULL != symbol_size) *symbol_size = sym->st_size;
651 | return (void *)(self->load_bias + sym->st_value);
652 | }
653 |
654 | void *xdl_dsym(void *handle, const char *symbol, size_t *symbol_size) {
655 | if (NULL == handle || NULL == symbol) return NULL;
656 | if (NULL != symbol_size) *symbol_size = 0;
657 |
658 | xdl_t *self = (xdl_t *)handle;
659 |
660 | // load .symtab only once
661 | if (!self->symtab_try_load) {
662 | self->symtab_try_load = true;
663 | if (0 != xdl_symtab_load(self)) return NULL;
664 | }
665 |
666 | // find symbol
667 | if (NULL == self->symtab) return NULL;
668 | for (size_t i = 0; i < self->symtab_cnt; i++) {
669 | ElfW(Sym) *sym = self->symtab + i;
670 |
671 | if (!XDL_SYMTAB_IS_EXPORT_SYM(sym->st_shndx)) continue;
672 | if (0 != strncmp(self->strtab + sym->st_name, symbol, self->strtab_sz - sym->st_name)) continue;
673 |
674 | if (NULL != symbol_size) *symbol_size = sym->st_size;
675 | return (void *)(self->load_bias + sym->st_value);
676 | }
677 |
678 | return NULL;
679 | }
680 |
681 | static bool xdl_elf_is_match(uintptr_t load_bias, const ElfW(Phdr) *dlpi_phdr, ElfW(Half) dlpi_phnum,
682 | uintptr_t addr) {
683 | if (addr < load_bias) return false;
684 |
685 | uintptr_t vaddr = addr - load_bias;
686 | for (size_t i = 0; i < dlpi_phnum; i++) {
687 | const ElfW(Phdr) *phdr = &(dlpi_phdr[i]);
688 | if (PT_LOAD != phdr->p_type) continue;
689 |
690 | if (phdr->p_vaddr <= vaddr && vaddr < phdr->p_vaddr + phdr->p_memsz) return true;
691 | }
692 |
693 | return false;
694 | }
695 |
696 | static int xdl_open_by_addr_iterate_cb(struct dl_phdr_info *info, size_t size, void *arg) {
697 | (void)size;
698 |
699 | uintptr_t *pkg = (uintptr_t *)arg;
700 | xdl_t **self = (xdl_t **)*pkg++;
701 | uintptr_t addr = *pkg;
702 |
703 | if (xdl_elf_is_match(info->dlpi_addr, info->dlpi_phdr, info->dlpi_phnum, addr)) {
704 | // found the target ELF
705 | if (NULL == ((*self) = calloc(1, sizeof(xdl_t)))) return 1; // failed
706 | if (NULL == ((*self)->pathname = strdup(info->dlpi_name))) {
707 | free(*self);
708 | *self = NULL;
709 | return 1; // failed
710 | }
711 | (*self)->load_bias = info->dlpi_addr;
712 | (*self)->dlpi_phdr = info->dlpi_phdr;
713 | (*self)->dlpi_phnum = info->dlpi_phnum;
714 | (*self)->dynsym_try_load = false;
715 | (*self)->symtab_try_load = false;
716 | return 1; // OK
717 | }
718 |
719 | return 0; // mismatch
720 | }
721 |
722 | static void *xdl_open_by_addr(void *addr) {
723 | if (NULL == addr) return NULL;
724 |
725 | xdl_t *self = NULL;
726 | uintptr_t pkg[2] = {(uintptr_t)&self, (uintptr_t)addr};
727 | xdl_iterate_phdr(xdl_open_by_addr_iterate_cb, pkg, XDL_DEFAULT);
728 |
729 | return (void *)self;
730 | }
731 |
732 | static bool xdl_sym_is_match(ElfW(Sym) *sym, uintptr_t offset, bool is_symtab) {
733 | if (is_symtab) {
734 | if (!XDL_SYMTAB_IS_EXPORT_SYM(sym->st_shndx)) false;
735 | } else {
736 | if (!XDL_DYNSYM_IS_EXPORT_SYM(sym->st_shndx)) false;
737 | }
738 |
739 | return ELF_ST_TYPE(sym->st_info) != STT_TLS && offset >= sym->st_value &&
740 | offset < sym->st_value + sym->st_size;
741 | }
742 |
743 | static ElfW(Sym) *xdl_sym_by_addr(void *handle, void *addr) {
744 | xdl_t *self = (xdl_t *)handle;
745 |
746 | // load .dynsym only once
747 | if (!self->dynsym_try_load) {
748 | self->dynsym_try_load = true;
749 | if (0 != xdl_dynsym_load(self)) return NULL;
750 | }
751 |
752 | // find symbol
753 | if (NULL == self->dynsym) return NULL;
754 | uintptr_t offset = (uintptr_t)addr - self->load_bias;
755 | if (self->gnu_hash.buckets_cnt > 0) {
756 | const uint32_t *chains_all = self->gnu_hash.chains - self->gnu_hash.symoffset;
757 | for (size_t i = 0; i < self->gnu_hash.buckets_cnt; i++) {
758 | uint32_t n = self->gnu_hash.buckets[i];
759 | if (n < self->gnu_hash.symoffset) continue;
760 | do {
761 | ElfW(Sym) *sym = self->dynsym + n;
762 | if (xdl_sym_is_match(sym, offset, false)) return sym;
763 | } while ((chains_all[n++] & 1) == 0);
764 | }
765 | } else if (self->sysv_hash.chains_cnt > 0) {
766 | for (size_t i = 0; i < self->sysv_hash.chains_cnt; i++) {
767 | ElfW(Sym) *sym = self->dynsym + i;
768 | if (xdl_sym_is_match(sym, offset, false)) return sym;
769 | }
770 | }
771 |
772 | return NULL;
773 | }
774 |
775 | static ElfW(Sym) *xdl_dsym_by_addr(void *handle, void *addr) {
776 | xdl_t *self = (xdl_t *)handle;
777 |
778 | // load .symtab only once
779 | if (!self->symtab_try_load) {
780 | self->symtab_try_load = true;
781 | if (0 != xdl_symtab_load(self)) return NULL;
782 | }
783 |
784 | // find symbol
785 | if (NULL == self->symtab) return NULL;
786 | uintptr_t offset = (uintptr_t)addr - self->load_bias;
787 | for (size_t i = 0; i < self->symtab_cnt; i++) {
788 | ElfW(Sym) *sym = self->symtab + i;
789 | if (xdl_sym_is_match(sym, offset, true)) return sym;
790 | }
791 |
792 | return NULL;
793 | }
794 |
795 | int xdl_addr(void *addr, xdl_info_t *info, void **cache) {
796 | if (NULL == addr || NULL == info || NULL == cache) return 0;
797 |
798 | memset(info, 0, sizeof(Dl_info));
799 |
800 | // find handle from cache
801 | xdl_t *handle = NULL;
802 | for (handle = *((xdl_t **)cache); NULL != handle; handle = handle->next)
803 | if (xdl_elf_is_match(handle->load_bias, handle->dlpi_phdr, handle->dlpi_phnum, (uintptr_t)addr)) break;
804 |
805 | // create new handle, save handle to cache
806 | if (NULL == handle) {
807 | handle = (xdl_t *)xdl_open_by_addr(addr);
808 | if (NULL == handle) return 0;
809 | handle->next = *(xdl_t **)cache;
810 | *(xdl_t **)cache = handle;
811 | }
812 |
813 | // we have at least: load_bias, pathname, dlpi_phdr, dlpi_phnum
814 | info->dli_fbase = (void *)handle->load_bias;
815 | info->dli_fname = handle->pathname;
816 | info->dli_sname = NULL;
817 | info->dli_saddr = 0;
818 | info->dli_ssize = 0;
819 | info->dlpi_phdr = handle->dlpi_phdr;
820 | info->dlpi_phnum = (size_t)handle->dlpi_phnum;
821 |
822 | // keep looking for: symbol name, symbol offset, symbol size
823 | ElfW(Sym) *sym;
824 | if (NULL != (sym = xdl_sym_by_addr((void *)handle, addr))) {
825 | info->dli_sname = handle->dynstr + sym->st_name;
826 | info->dli_saddr = (void *)(handle->load_bias + sym->st_value);
827 | info->dli_ssize = sym->st_size;
828 | } else if (NULL != (sym = xdl_dsym_by_addr((void *)handle, addr))) {
829 | info->dli_sname = handle->strtab + sym->st_name;
830 | info->dli_saddr = (void *)(handle->load_bias + sym->st_value);
831 | info->dli_ssize = sym->st_size;
832 | }
833 |
834 | return 1;
835 | }
836 |
837 | void xdl_addr_clean(void **cache) {
838 | if (NULL == cache) return;
839 |
840 | xdl_t *handle = *((xdl_t **)cache);
841 | while (NULL != handle) {
842 | xdl_t *tmp = handle;
843 | handle = handle->next;
844 | xdl_close(tmp);
845 | }
846 | *cache = NULL;
847 | }
848 |
849 | int xdl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *), void *data, int flags) {
850 | if (NULL == callback) return 0;
851 |
852 | return xdl_iterate_phdr_impl(callback, data, flags);
853 | }
854 |
855 | int xdl_info(void *handle, int request, void *info) {
856 | if (NULL == handle || XDL_DI_DLINFO != request || NULL == info) return -1;
857 |
858 | xdl_t *self = (xdl_t *)handle;
859 | xdl_info_t *dlinfo = (xdl_info_t *)info;
860 |
861 | dlinfo->dli_fbase = (void *)self->load_bias;
862 | dlinfo->dli_fname = self->pathname;
863 | dlinfo->dli_sname = NULL;
864 | dlinfo->dli_saddr = 0;
865 | dlinfo->dli_ssize = 0;
866 | dlinfo->dlpi_phdr = self->dlpi_phdr;
867 | dlinfo->dlpi_phnum = (size_t)self->dlpi_phnum;
868 | return 0;
869 | }
870 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl_iterate.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2020-10-04.
23 |
24 | #include "xdl_iterate.h"
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 | #include
36 | #include
37 | #include
38 |
39 | #include "xdl.h"
40 | #include "xdl_linker.h"
41 | #include "xdl_util.h"
42 |
43 | /*
44 | * =========================================================================================================
45 | * API-LEVEL ANDROID-VERSION SOLUTION
46 | * =========================================================================================================
47 | * 16 4.1 /proc/self/maps
48 | * 17 4.2 /proc/self/maps
49 | * 18 4.3 /proc/self/maps
50 | * 19 4.4 /proc/self/maps
51 | * 20 4.4W /proc/self/maps
52 | * ---------------------------------------------------------------------------------------------------------
53 | * 21 5.0 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3)
54 | * 22 5.1 dl_iterate_phdr() + __dl__ZL10g_dl_mutex + linker/linker64 from getauxval(3)
55 | * ---------------------------------------------------------------------------------------------------------
56 | * 23 >= 6.0 dl_iterate_phdr() + linker/linker64 from getauxval(3)
57 | * =========================================================================================================
58 | */
59 |
60 | extern __attribute((weak)) int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *);
61 | extern __attribute((weak)) unsigned long int getauxval(unsigned long int);
62 |
63 | static uintptr_t xdl_iterate_get_min_vaddr(struct dl_phdr_info *info) {
64 | uintptr_t min_vaddr = UINTPTR_MAX;
65 | for (size_t i = 0; i < info->dlpi_phnum; i++) {
66 | const ElfW(Phdr) *phdr = &(info->dlpi_phdr[i]);
67 | if (PT_LOAD == phdr->p_type) {
68 | if (min_vaddr > phdr->p_vaddr) min_vaddr = phdr->p_vaddr;
69 | }
70 | }
71 | return min_vaddr;
72 | }
73 |
74 | static int xdl_iterate_open_or_rewind_maps(FILE **maps) {
75 | if (NULL == *maps) {
76 | *maps = fopen("/proc/self/maps", "r");
77 | if (NULL == *maps) return -1;
78 | } else
79 | rewind(*maps);
80 |
81 | return 0;
82 | }
83 |
84 | static int xdl_iterate_get_pathname_from_maps(uintptr_t base, char *buf, size_t buf_len, FILE **maps) {
85 | // open or rewind maps-file
86 | if (0 != xdl_iterate_open_or_rewind_maps(maps)) return -1; // failed
87 |
88 | char line[1024];
89 | while (fgets(line, sizeof(line), *maps)) {
90 | // check base address
91 | uintptr_t start, end;
92 | if (2 != sscanf(line, "%" SCNxPTR "-%" SCNxPTR " r", &start, &end)) continue;
93 | if (base < start) break; // failed
94 | if (base >= end) continue;
95 |
96 | // get pathname
97 | char *pathname = strchr(line, '/');
98 | if (NULL == pathname) break; // failed
99 | xdl_util_trim_ending(pathname);
100 |
101 | // found it
102 | strlcpy(buf, pathname, buf_len);
103 | return 0; // OK
104 | }
105 |
106 | return -1; // failed
107 | }
108 |
109 | static int xdl_iterate_by_linker_cb(struct dl_phdr_info *info, size_t size, void *arg) {
110 | uintptr_t *pkg = (uintptr_t *)arg;
111 | xdl_iterate_phdr_cb_t cb = (xdl_iterate_phdr_cb_t)*pkg++;
112 | void *cb_arg = (void *)*pkg++;
113 | FILE **maps = (FILE **)*pkg++;
114 | uintptr_t linker_load_bias = *pkg++;
115 | int flags = (int)*pkg;
116 |
117 | // ignore invalid ELF
118 | if (0 == info->dlpi_addr || NULL == info->dlpi_name || '\0' == info->dlpi_name[0]) return 0;
119 |
120 | // ignore linker if we have returned it already
121 | if (linker_load_bias == info->dlpi_addr) return 0;
122 |
123 | struct dl_phdr_info info_fixed;
124 | info_fixed.dlpi_addr = info->dlpi_addr;
125 | info_fixed.dlpi_name = info->dlpi_name;
126 | info_fixed.dlpi_phdr = info->dlpi_phdr;
127 | info_fixed.dlpi_phnum = info->dlpi_phnum;
128 | info = &info_fixed;
129 |
130 | // fix dlpi_phdr & dlpi_phnum (from memory)
131 | if (NULL == info->dlpi_phdr || 0 == info->dlpi_phnum) {
132 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)info->dlpi_addr;
133 | info->dlpi_phdr = (ElfW(Phdr) *)(info->dlpi_addr + ehdr->e_phoff);
134 | info->dlpi_phnum = ehdr->e_phnum;
135 | }
136 |
137 | // fix dlpi_name (from /proc/self/maps)
138 | if ('/' != info->dlpi_name[0] && '[' != info->dlpi_name[0] && (0 != (flags & XDL_FULL_PATHNAME))) {
139 | // get base address
140 | uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(info);
141 | if (UINTPTR_MAX == min_vaddr) return 0; // ignore this ELF
142 | uintptr_t base = (uintptr_t)(info->dlpi_addr + min_vaddr);
143 |
144 | char buf[1024];
145 | if (0 != xdl_iterate_get_pathname_from_maps(base, buf, sizeof(buf), maps)) return 0; // ignore this ELF
146 |
147 | info->dlpi_name = (const char *)buf;
148 | }
149 |
150 | // callback
151 | return cb(info, size, cb_arg);
152 | }
153 |
154 | static uintptr_t xdl_iterate_get_linker_base(void) {
155 | if (NULL == getauxval) return 0;
156 |
157 | uintptr_t base = (uintptr_t)getauxval(AT_BASE);
158 | if (0 == base) return 0;
159 | if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) return 0;
160 |
161 | return base;
162 | }
163 |
164 | static int xdl_iterate_do_callback(xdl_iterate_phdr_cb_t cb, void *cb_arg, uintptr_t base,
165 | const char *pathname, uintptr_t *load_bias) {
166 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base;
167 |
168 | struct dl_phdr_info info;
169 | info.dlpi_name = pathname;
170 | info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff);
171 | info.dlpi_phnum = ehdr->e_phnum;
172 |
173 | // get load bias
174 | uintptr_t min_vaddr = xdl_iterate_get_min_vaddr(&info);
175 | if (UINTPTR_MAX == min_vaddr) return 0; // ignore invalid ELF
176 | info.dlpi_addr = (ElfW(Addr))(base - min_vaddr);
177 | if (NULL != load_bias) *load_bias = info.dlpi_addr;
178 |
179 | return cb(&info, sizeof(struct dl_phdr_info), cb_arg);
180 | }
181 |
182 | static int xdl_iterate_by_linker(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags) {
183 | if (NULL == dl_iterate_phdr) return 0;
184 |
185 | int api_level = xdl_util_get_api_level();
186 | FILE *maps = NULL;
187 | int r;
188 |
189 | // dl_iterate_phdr(3) does NOT contain linker/linker64 when Android version < 8.1 (API level 27).
190 | // Here we always try to get linker base address from auxv.
191 | uintptr_t linker_load_bias = 0;
192 | uintptr_t linker_base = xdl_iterate_get_linker_base();
193 | if (0 != linker_base) {
194 | if (0 !=
195 | (r = xdl_iterate_do_callback(cb, cb_arg, linker_base, XDL_UTIL_LINKER_PATHNAME, &linker_load_bias)))
196 | return r;
197 | }
198 |
199 | // for other ELF
200 | uintptr_t pkg[5] = {(uintptr_t)cb, (uintptr_t)cb_arg, (uintptr_t)&maps, linker_load_bias, (uintptr_t)flags};
201 | if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) xdl_linker_lock();
202 | r = dl_iterate_phdr(xdl_iterate_by_linker_cb, pkg);
203 | if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) xdl_linker_unlock();
204 |
205 | if (NULL != maps) fclose(maps);
206 | return r;
207 | }
208 |
209 | #if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__
210 | static int xdl_iterate_by_maps(xdl_iterate_phdr_cb_t cb, void *cb_arg) {
211 | FILE *maps = fopen("/proc/self/maps", "r");
212 | if (NULL == maps) return 0;
213 |
214 | int r = 0;
215 | char buf1[1024], buf2[1024];
216 | char *line = buf1;
217 | uintptr_t prev_base = 0;
218 | bool try_next_line = false;
219 |
220 | while (fgets(line, sizeof(buf1), maps)) {
221 | // Try to find an ELF which loaded by linker.
222 | uintptr_t base, offset;
223 | char exec;
224 | if (3 != sscanf(line, "%" SCNxPTR "-%*" SCNxPTR " r%*c%cp %" SCNxPTR " ", &base, &exec, &offset)) goto clean;
225 |
226 | if ('-' == exec && 0 == offset) {
227 | // r--p
228 | prev_base = base;
229 | line = (line == buf1 ? buf2 : buf1);
230 | try_next_line = true;
231 | continue;
232 | }
233 | else if (exec == 'x') {
234 | // r-xp
235 | char *pathname = NULL;
236 | if (try_next_line && 0 != offset) {
237 | char *prev = (line == buf1 ? buf2 : buf1);
238 | char *prev_pathname = strchr(prev, '/');
239 | if (NULL == prev_pathname) goto clean;
240 |
241 | pathname = strchr(line, '/');
242 | if (NULL == pathname) goto clean;
243 |
244 | xdl_util_trim_ending(prev_pathname);
245 | xdl_util_trim_ending(pathname);
246 | if (0 != strcmp(prev_pathname, pathname)) goto clean;
247 |
248 | // we found the line with r-xp in the next line
249 | base = prev_base;
250 | offset = 0;
251 | }
252 |
253 | if (0 != offset) goto clean;
254 |
255 | // get pathname
256 | if (NULL == pathname) {
257 | pathname = strchr(line, '/');
258 | if (NULL == pathname) goto clean;
259 | xdl_util_trim_ending(pathname);
260 | }
261 |
262 | if (0 != memcmp((void *)base, ELFMAG, SELFMAG)) goto clean;
263 | ElfW(Ehdr) *ehdr = (ElfW(Ehdr) *)base;
264 | struct dl_phdr_info info;
265 | info.dlpi_name = pathname;
266 | info.dlpi_phdr = (const ElfW(Phdr) *)(base + ehdr->e_phoff);
267 | info.dlpi_phnum = ehdr->e_phnum;
268 |
269 | // callback
270 | if (0 != (r = xdl_iterate_do_callback(cb, cb_arg, base, pathname, NULL))) break;
271 | }
272 |
273 | clean:
274 | try_next_line = false;
275 | }
276 |
277 | fclose(maps);
278 | return r;
279 | }
280 | #endif
281 |
282 | int xdl_iterate_phdr_impl(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags) {
283 | // iterate by /proc/self/maps in Android 4.x (Android 4.x only supports arm32 and x86)
284 | #if (defined(__arm__) || defined(__i386__)) && __ANDROID_API__ < __ANDROID_API_L__
285 | if (xdl_util_get_api_level() < __ANDROID_API_L__) return xdl_iterate_by_maps(cb, cb_arg);
286 | #endif
287 |
288 | // iterate by dl_iterate_phdr()
289 | return xdl_iterate_by_linker(cb, cb_arg, flags);
290 | }
291 |
292 | int xdl_iterate_get_full_pathname(uintptr_t base, char *buf, size_t buf_len) {
293 | FILE *maps = NULL;
294 | int r = xdl_iterate_get_pathname_from_maps(base, buf, buf_len, &maps);
295 | if (NULL != maps) fclose(maps);
296 | return r;
297 | }
298 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl_iterate.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2020-10-04.
23 |
24 | #ifndef IO_HEXHACKING_XDL_ITERATE
25 | #define IO_HEXHACKING_XDL_ITERATE
26 |
27 | #include
28 | #include
29 |
30 | #ifdef __cplusplus
31 | extern "C" {
32 | #endif
33 |
34 | typedef int (*xdl_iterate_phdr_cb_t)(struct dl_phdr_info *info, size_t size, void *arg);
35 | int xdl_iterate_phdr_impl(xdl_iterate_phdr_cb_t cb, void *cb_arg, int flags);
36 |
37 | int xdl_iterate_get_full_pathname(uintptr_t base, char *buf, size_t buf_len);
38 |
39 | #ifdef __cplusplus
40 | }
41 | #endif
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl_linker.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2021-02-21.
23 |
24 | #include "xdl_linker.h"
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 |
31 | #include "xdl.h"
32 | #include "xdl_iterate.h"
33 | #include "xdl_util.h"
34 |
35 | #define XDL_LINKER_SYM_MUTEX "__dl__ZL10g_dl_mutex"
36 | #define XDL_LINKER_SYM_DLOPEN_EXT_N "__dl__ZL10dlopen_extPKciPK17android_dlextinfoPv"
37 | #define XDL_LINKER_SYM_DO_DLOPEN_N "__dl__Z9do_dlopenPKciPK17android_dlextinfoPv"
38 | #define XDL_LINKER_SYM_DLOPEN_O "__dl__Z8__dlopenPKciPKv"
39 | #define XDL_LINKER_SYM_LOADER_DLOPEN_P "__loader_dlopen"
40 |
41 | typedef void *(*xdl_linker_dlopen_n_t)(const char *, int, const void *, void *);
42 | typedef void *(*xdl_linker_dlopen_o_t)(const char *, int, const void *);
43 |
44 | static pthread_mutex_t *xdl_linker_mutex = NULL;
45 | static void *xdl_linker_dlopen = NULL;
46 |
47 | static void *xdl_linker_caller_addr[] = {
48 | NULL, // default
49 | NULL, // art
50 | NULL // vendor
51 | };
52 |
53 | #ifndef __LP64__
54 | #define XDL_LINKER_LIB "lib"
55 | #else
56 | #define XDL_LINKER_LIB "lib64"
57 | #endif
58 | static const char *xdl_linker_vendor_path[] = {
59 | // order is important
60 | "/vendor/" XDL_LINKER_LIB "/egl/", "/vendor/" XDL_LINKER_LIB "/hw/",
61 | "/vendor/" XDL_LINKER_LIB "/", "/odm/" XDL_LINKER_LIB "/",
62 | "/vendor/" XDL_LINKER_LIB "/vndk-sp/", "/odm/" XDL_LINKER_LIB "/vndk-sp/"};
63 |
64 | static void xdl_linker_init(void) {
65 | static bool inited = false;
66 | if (inited) return;
67 | inited = true;
68 |
69 | void *handle = xdl_open(XDL_UTIL_LINKER_BASENAME, XDL_DEFAULT);
70 | if (NULL == handle) return;
71 |
72 | int api_level = xdl_util_get_api_level();
73 | if (__ANDROID_API_L__ == api_level || __ANDROID_API_L_MR1__ == api_level) {
74 | // == Android 5.x
75 | xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL);
76 | } else if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) {
77 | // == Android 7.x
78 | xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_EXT_N, NULL);
79 | if (NULL == xdl_linker_dlopen) {
80 | xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DO_DLOPEN_N, NULL);
81 | xdl_linker_mutex = (pthread_mutex_t *)xdl_dsym(handle, XDL_LINKER_SYM_MUTEX, NULL);
82 | }
83 | } else if (__ANDROID_API_O__ == api_level || __ANDROID_API_O_MR1__ == api_level) {
84 | // == Android 8.x
85 | xdl_linker_dlopen = xdl_dsym(handle, XDL_LINKER_SYM_DLOPEN_O, NULL);
86 | } else if (api_level >= __ANDROID_API_P__) {
87 | // >= Android 9.0
88 | xdl_linker_dlopen = xdl_sym(handle, XDL_LINKER_SYM_LOADER_DLOPEN_P, NULL);
89 | }
90 |
91 | xdl_close(handle);
92 | }
93 |
94 | void xdl_linker_lock(void) {
95 | xdl_linker_init();
96 |
97 | if (NULL != xdl_linker_mutex) pthread_mutex_lock(xdl_linker_mutex);
98 | }
99 |
100 | void xdl_linker_unlock(void) {
101 | if (NULL != xdl_linker_mutex) pthread_mutex_unlock(xdl_linker_mutex);
102 | }
103 |
104 | static void *xdl_linker_get_caller_addr(struct dl_phdr_info *info) {
105 | for (size_t i = 0; i < info->dlpi_phnum; i++) {
106 | const ElfW(Phdr) *phdr = &(info->dlpi_phdr[i]);
107 | if (PT_LOAD == phdr->p_type) {
108 | return (void *)(info->dlpi_addr + phdr->p_vaddr);
109 | }
110 | }
111 | return NULL;
112 | }
113 |
114 | static int xdl_linker_get_caller_addr_cb(struct dl_phdr_info *info, size_t size, void *arg) {
115 | (void)size;
116 |
117 | size_t *vendor_match = (size_t *)arg;
118 |
119 | if (0 == info->dlpi_addr || NULL == info->dlpi_name) return 0; // continue
120 |
121 | if (NULL == xdl_linker_caller_addr[0] && xdl_util_ends_with(info->dlpi_name, "/libc.so"))
122 | xdl_linker_caller_addr[0] = xdl_linker_get_caller_addr(info);
123 |
124 | if (NULL == xdl_linker_caller_addr[1] && xdl_util_ends_with(info->dlpi_name, "/libart.so"))
125 | xdl_linker_caller_addr[1] = xdl_linker_get_caller_addr(info);
126 |
127 | if (0 != *vendor_match) {
128 | for (size_t i = 0; i < *vendor_match; i++) {
129 | if (xdl_util_starts_with(info->dlpi_name, xdl_linker_vendor_path[i])) {
130 | void *caller_addr = xdl_linker_get_caller_addr(info);
131 | if (NULL != caller_addr) {
132 | xdl_linker_caller_addr[2] = caller_addr;
133 | *vendor_match = i;
134 | }
135 | }
136 | }
137 | }
138 |
139 | if (NULL != xdl_linker_caller_addr[0] && NULL != xdl_linker_caller_addr[1] && 0 == *vendor_match) {
140 | return 1; // finish
141 | } else {
142 | return 0; // continue
143 | }
144 | }
145 |
146 | static void xdl_linker_load_caller_addr(void) {
147 | if (NULL == xdl_linker_caller_addr[0]) {
148 | size_t vendor_match = sizeof(xdl_linker_vendor_path) / sizeof(xdl_linker_vendor_path[0]);
149 | xdl_iterate_phdr_impl(xdl_linker_get_caller_addr_cb, &vendor_match, XDL_DEFAULT);
150 | }
151 | }
152 |
153 | void *xdl_linker_load(const char *filename) {
154 | int api_level = xdl_util_get_api_level();
155 |
156 | if (api_level <= __ANDROID_API_M__) {
157 | // <= Android 6.0
158 | return dlopen(filename, RTLD_NOW);
159 | } else {
160 | xdl_linker_init();
161 | if (NULL == xdl_linker_dlopen) return NULL;
162 | xdl_linker_load_caller_addr();
163 |
164 | void *handle = NULL;
165 | if (__ANDROID_API_N__ == api_level || __ANDROID_API_N_MR1__ == api_level) {
166 | // == Android 7.x
167 | xdl_linker_lock();
168 | for (size_t i = 0; i < sizeof(xdl_linker_caller_addr) / sizeof(xdl_linker_caller_addr[0]); i++) {
169 | if (NULL != xdl_linker_caller_addr[i]) {
170 | handle =
171 | ((xdl_linker_dlopen_n_t)xdl_linker_dlopen)(filename, RTLD_NOW, NULL, xdl_linker_caller_addr[i]);
172 | if (NULL != handle) break;
173 | }
174 | }
175 | xdl_linker_unlock();
176 | } else {
177 | // >= Android 8.0
178 | for (size_t i = 0; i < sizeof(xdl_linker_caller_addr) / sizeof(xdl_linker_caller_addr[0]); i++) {
179 | if (NULL != xdl_linker_caller_addr[i]) {
180 | handle = ((xdl_linker_dlopen_o_t)xdl_linker_dlopen)(filename, RTLD_NOW, xdl_linker_caller_addr[i]);
181 | if (NULL != handle) break;
182 | }
183 | }
184 | }
185 | return handle;
186 | }
187 | }
188 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl_linker.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2021-02-21.
23 |
24 | #ifndef IO_HEXHACKING_XDL_LINKER
25 | #define IO_HEXHACKING_XDL_LINKER
26 |
27 | #ifdef __cplusplus
28 | extern "C" {
29 | #endif
30 |
31 | void xdl_linker_lock(void);
32 | void xdl_linker_unlock(void);
33 |
34 | void *xdl_linker_load(const char *filename);
35 |
36 | #ifdef __cplusplus
37 | }
38 | #endif
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl_lzma.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2020-11-08.
23 |
24 | #include "xdl_lzma.h"
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 |
35 | #include "xdl.h"
36 | #include "xdl_util.h"
37 |
38 | // LZMA library pathname & symbol names
39 | #ifndef __LP64__
40 | #define XDL_LZMA_PATHNAME "/system/lib/liblzma.so"
41 | #else
42 | #define XDL_LZMA_PATHNAME "/system/lib64/liblzma.so"
43 | #endif
44 | #define XDL_LZMA_SYM_CRCGEN "CrcGenerateTable"
45 | #define XDL_LZMA_SYM_CRC64GEN "Crc64GenerateTable"
46 | #define XDL_LZMA_SYM_CONSTRUCT "XzUnpacker_Construct"
47 | #define XDL_LZMA_SYM_ISFINISHED "XzUnpacker_IsStreamWasFinished"
48 | #define XDL_LZMA_SYM_FREE "XzUnpacker_Free"
49 | #define XDL_LZMA_SYM_CODE "XzUnpacker_Code"
50 |
51 | // LZMA data type definition
52 | #define SZ_OK 0
53 | typedef struct ISzAlloc ISzAlloc;
54 | typedef const ISzAlloc *ISzAllocPtr;
55 | struct ISzAlloc {
56 | void *(*Alloc)(ISzAllocPtr p, size_t size);
57 | void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
58 | };
59 | typedef enum {
60 | CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
61 | CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
62 | CODER_STATUS_NOT_FINISHED, /* stream was not finished */
63 | CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
64 | } ECoderStatus;
65 | typedef enum {
66 | CODER_FINISH_ANY, /* finish at any point */
67 | CODER_FINISH_END /* block must be finished at the end */
68 | } ECoderFinishMode;
69 |
70 | // LZMA function type definition
71 | typedef void (*xdl_lzma_crcgen_t)(void);
72 | typedef void (*xdl_lzma_crc64gen_t)(void);
73 | typedef void (*xdl_lzma_construct_t)(void *, ISzAllocPtr);
74 | typedef int (*xdl_lzma_isfinished_t)(const void *);
75 | typedef void (*xdl_lzma_free_t)(void *);
76 | typedef int (*xdl_lzma_code_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, ECoderFinishMode,
77 | ECoderStatus *);
78 | typedef int (*xdl_lzma_code_q_t)(void *, uint8_t *, size_t *, const uint8_t *, size_t *, int,
79 | ECoderFinishMode, ECoderStatus *);
80 |
81 | // LZMA function pointor
82 | static xdl_lzma_construct_t xdl_lzma_construct = NULL;
83 | static xdl_lzma_isfinished_t xdl_lzma_isfinished = NULL;
84 | static xdl_lzma_free_t xdl_lzma_free = NULL;
85 | static void *xdl_lzma_code = NULL;
86 |
87 | // LZMA init
88 | static void xdl_lzma_init() {
89 | void *lzma = xdl_open(XDL_LZMA_PATHNAME, XDL_TRY_FORCE_LOAD);
90 | if (NULL == lzma) return;
91 |
92 | xdl_lzma_crcgen_t crcgen = NULL;
93 | xdl_lzma_crc64gen_t crc64gen = NULL;
94 | if (NULL == (crcgen = (xdl_lzma_crcgen_t)xdl_sym(lzma, XDL_LZMA_SYM_CRCGEN, NULL))) goto end;
95 | if (NULL == (crc64gen = (xdl_lzma_crc64gen_t)xdl_sym(lzma, XDL_LZMA_SYM_CRC64GEN, NULL))) goto end;
96 | if (NULL == (xdl_lzma_construct = (xdl_lzma_construct_t)xdl_sym(lzma, XDL_LZMA_SYM_CONSTRUCT, NULL)))
97 | goto end;
98 | if (NULL == (xdl_lzma_isfinished = (xdl_lzma_isfinished_t)xdl_sym(lzma, XDL_LZMA_SYM_ISFINISHED, NULL)))
99 | goto end;
100 | if (NULL == (xdl_lzma_free = (xdl_lzma_free_t)xdl_sym(lzma, XDL_LZMA_SYM_FREE, NULL))) goto end;
101 | if (NULL == (xdl_lzma_code = xdl_sym(lzma, XDL_LZMA_SYM_CODE, NULL))) goto end;
102 | crcgen();
103 | crc64gen();
104 |
105 | end:
106 | xdl_close(lzma);
107 | }
108 |
109 | // LZMA internal alloc / free
110 | static void *xdl_lzma_internal_alloc(ISzAllocPtr p, size_t size) {
111 | (void)p;
112 | return malloc(size);
113 | }
114 | static void xdl_lzma_internal_free(ISzAllocPtr p, void *address) {
115 | (void)p;
116 | free(address);
117 | }
118 |
119 | int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *dst_size) {
120 | size_t src_offset = 0;
121 | size_t dst_offset = 0;
122 | size_t src_remaining;
123 | size_t dst_remaining;
124 | ISzAlloc alloc = {.Alloc = xdl_lzma_internal_alloc, .Free = xdl_lzma_internal_free};
125 | long long state[4096 / sizeof(long long)]; // must be enough, 8-bit aligned
126 | ECoderStatus status;
127 | int api_level = xdl_util_get_api_level();
128 |
129 | // init and check
130 | static bool inited = false;
131 | if (!inited) {
132 | xdl_lzma_init();
133 | inited = true;
134 | }
135 | if (NULL == xdl_lzma_code) return -1;
136 |
137 | xdl_lzma_construct(&state, &alloc);
138 |
139 | *dst_size = 2 * src_size;
140 | *dst = NULL;
141 | do {
142 | *dst_size *= 2;
143 | if (NULL == (*dst = realloc(*dst, *dst_size))) {
144 | xdl_lzma_free(&state);
145 | return -1;
146 | }
147 |
148 | src_remaining = src_size - src_offset;
149 | dst_remaining = *dst_size - dst_offset;
150 |
151 | int result;
152 | if (api_level >= __ANDROID_API_Q__) {
153 | xdl_lzma_code_q_t lzma_code_q = (xdl_lzma_code_q_t)xdl_lzma_code;
154 | result = lzma_code_q(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining, 1,
155 | CODER_FINISH_ANY, &status);
156 | } else {
157 | xdl_lzma_code_t lzma_code = (xdl_lzma_code_t)xdl_lzma_code;
158 | result = lzma_code(&state, *dst + dst_offset, &dst_remaining, src + src_offset, &src_remaining,
159 | CODER_FINISH_ANY, &status);
160 | }
161 | if (SZ_OK != result) {
162 | free(*dst);
163 | xdl_lzma_free(&state);
164 | return -1;
165 | }
166 |
167 | src_offset += src_remaining;
168 | dst_offset += dst_remaining;
169 | } while (status == CODER_STATUS_NOT_FINISHED);
170 |
171 | xdl_lzma_free(&state);
172 |
173 | if (!xdl_lzma_isfinished(&state)) {
174 | free(*dst);
175 | return -1;
176 | }
177 |
178 | *dst_size = dst_offset;
179 | *dst = realloc(*dst, *dst_size);
180 | return 0;
181 | }
182 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl_lzma.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2020-11-08.
23 |
24 | #ifndef IO_HEXHACKING_XDL_LZMA
25 | #define IO_HEXHACKING_XDL_LZMA
26 |
27 | #include
28 | #include
29 |
30 | #ifdef __cplusplus
31 | extern "C" {
32 | #endif
33 |
34 | int xdl_lzma_decompress(uint8_t *src, size_t src_size, uint8_t **dst, size_t *dst_size);
35 |
36 | #ifdef __cplusplus
37 | }
38 | #endif
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl_util.c:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2020-10-04.
23 |
24 | #include "xdl_util.h"
25 |
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 | #include
32 | #include
33 | #include
34 | #include
35 |
36 | bool xdl_util_starts_with(const char *str, const char *start) {
37 | while (*str && *str == *start) {
38 | str++;
39 | start++;
40 | }
41 |
42 | return '\0' == *start;
43 | }
44 |
45 | bool xdl_util_ends_with(const char *str, const char *ending) {
46 | size_t str_len = strlen(str);
47 | size_t ending_len = strlen(ending);
48 |
49 | if (ending_len > str_len) return false;
50 |
51 | return 0 == strcmp(str + (str_len - ending_len), ending);
52 | }
53 |
54 | size_t xdl_util_trim_ending(char *start) {
55 | char *end = start + strlen(start);
56 | while (start < end && isspace((int)(*(end - 1)))) {
57 | end--;
58 | *end = '\0';
59 | }
60 | return (size_t)(end - start);
61 | }
62 |
63 | static int xdl_util_get_api_level_from_build_prop(void) {
64 | char buf[128];
65 | int api_level = -1;
66 |
67 | FILE *fp = fopen("/system/build.prop", "r");
68 | if (NULL == fp) goto end;
69 |
70 | while (fgets(buf, sizeof(buf), fp)) {
71 | if (xdl_util_starts_with(buf, "ro.build.version.sdk=")) {
72 | api_level = atoi(buf + 21);
73 | break;
74 | }
75 | }
76 | fclose(fp);
77 |
78 | end:
79 | return (api_level > 0) ? api_level : -1;
80 | }
81 |
82 | int xdl_util_get_api_level(void) {
83 | static int xdl_util_api_level = -1;
84 |
85 | if (xdl_util_api_level < 0) {
86 | int api_level = android_get_device_api_level();
87 | if (api_level < 0)
88 | api_level = xdl_util_get_api_level_from_build_prop(); // compatible with unusual models
89 | if (api_level < __ANDROID_API_J__) api_level = __ANDROID_API_J__;
90 |
91 | __atomic_store_n(&xdl_util_api_level, api_level, __ATOMIC_SEQ_CST);
92 | }
93 |
94 | return xdl_util_api_level;
95 | }
96 |
--------------------------------------------------------------------------------
/app/src/main/cpp/xdl/xdl_util.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-2021 HexHacking Team
2 | //
3 | // Permission is hereby granted, free of charge, to any person obtaining a copy
4 | // of this software and associated documentation files (the "Software"), to deal
5 | // in the Software without restriction, including without limitation the rights
6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | // copies of the Software, and to permit persons to whom the Software is
8 | // furnished to do so, subject to the following conditions:
9 | //
10 | // The above copyright notice and this permission notice shall be included in all
11 | // copies or substantial portions of the Software.
12 | //
13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | // SOFTWARE.
20 | //
21 |
22 | // Created by caikelun on 2020-10-04.
23 |
24 | #ifndef IO_HEXHACKING_XDL_UTIL
25 | #define IO_HEXHACKING_XDL_UTIL
26 |
27 | #include
28 | #include
29 | #include
30 |
31 | #ifndef __LP64__
32 | #define XDL_UTIL_LINKER_BASENAME "linker"
33 | #define XDL_UTIL_LINKER_PATHNAME "/system/bin/linker"
34 | #define XDL_UTIL_APP_PROCESS_BASENAME "app_process32"
35 | #define XDL_UTIL_APP_PROCESS_PATHNAME "/system/bin/app_process32"
36 | #define XDL_UTIL_APP_PROCESS_BASENAME_K "app_process"
37 | #define XDL_UTIL_APP_PROCESS_PATHNAME_K "/system/bin/app_process"
38 | #else
39 | #define XDL_UTIL_LINKER_BASENAME "linker64"
40 | #define XDL_UTIL_LINKER_PATHNAME "/system/bin/linker64"
41 | #define XDL_UTIL_APP_PROCESS_BASENAME "app_process64"
42 | #define XDL_UTIL_APP_PROCESS_PATHNAME "/system/bin/app_process64"
43 | #endif
44 | #define XDL_UTIL_VDSO_BASENAME "[vdso]"
45 |
46 | #define XDL_UTIL_TEMP_FAILURE_RETRY(exp) \
47 | ({ \
48 | __typeof__(exp) _rc; \
49 | do { \
50 | errno = 0; \
51 | _rc = (exp); \
52 | } while (_rc == -1 && errno == EINTR); \
53 | _rc; \
54 | })
55 |
56 | #ifdef __cplusplus
57 | extern "C" {
58 | #endif
59 |
60 | bool xdl_util_starts_with(const char *str, const char *start);
61 | bool xdl_util_ends_with(const char *str, const char *ending);
62 |
63 | size_t xdl_util_trim_ending(char *start);
64 |
65 | int xdl_util_get_api_level(void);
66 |
67 | #ifdef __cplusplus
68 | }
69 | #endif
70 |
71 | #endif
72 |
--------------------------------------------------------------------------------
/app/src/test/java/com/test/ptrace_il2cppdumper/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.test.ptrace_il2cppdumper;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/build.gradle.kts:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | plugins {
3 | alias(libs.plugins.android.application) apply false
4 | }
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. For more details, visit
12 | # https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app's APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Enables namespacing of each library's R class so that its R class includes only the
19 | # resources declared in the library itself and none from the library's dependencies,
20 | # thereby reducing the size of the R class for that library
21 | android.nonTransitiveRClass=true
--------------------------------------------------------------------------------
/gradle/libs.versions.toml:
--------------------------------------------------------------------------------
1 | [versions]
2 | agp = "8.8.0"
3 | junit = "4.13.2"
4 | junitVersion = "1.2.1"
5 | espressoCore = "3.6.1"
6 | appcompat = "1.7.0"
7 | material = "1.12.0"
8 | constraintlayout = "2.1.4"
9 |
10 | [libraries]
11 | junit = { group = "junit", name = "junit", version.ref = "junit" }
12 | ext-junit = { group = "androidx.test.ext", name = "junit", version.ref = "junitVersion" }
13 | espresso-core = { group = "androidx.test.espresso", name = "espresso-core", version.ref = "espressoCore" }
14 | appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
15 | material = { group = "com.google.android.material", name = "material", version.ref = "material" }
16 | constraintlayout = { group = "androidx.constraintlayout", name = "constraintlayout", version.ref = "constraintlayout" }
17 |
18 | [plugins]
19 | android-application = { id = "com.android.application", version.ref = "agp" }
20 |
21 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AndroidReverser-Test/PtraceIl2cppDumper/5c321b4d7f9e3186983724b090385ca52f0c424a/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Wed Mar 26 20:07:00 CST 2025
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
5 | zipStoreBase=GRADLE_USER_HOME
6 | zipStorePath=wrapper/dists
7 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
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 | # https://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 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/ida.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | def set_name(addr, name):
4 | new_name = name + '_' + hex(addr)
5 | idc.set_name(addr, new_name, SN_NOWARN | SN_NOCHECK)
6 |
7 | def make_function(start, end):
8 | next_func = idc.get_next_func(start)
9 | if next_func < end:
10 | end = next_func
11 | if idc.get_func_attr(start, FUNCATTR_START) == start:
12 | ida_funcs.del_func(start)
13 | ida_funcs.add_func(start, end)
14 |
15 | addresses = []
16 | fun_infos = []
17 | path = idaapi.ask_file(False, '*.txt', 'test_method_info.txt from PtraceIl2cppDumper')
18 |
19 |
20 | with open(path,"r",encoding="utf-8") as name_f:
21 | all_lines = name_f.readlines()
22 |
23 | for line in all_lines:
24 | if line == "":
25 | break
26 | # 确保地址有效
27 | item = line.split(":")
28 | if item[0] == "":
29 | continue
30 | fun_name = item[1].replace("\n","")
31 | fun_addr = int(item[0],16)
32 | addresses.append(fun_addr)
33 | fun_infos.append((fun_addr,fun_name))
34 |
35 | addresses.sort()
36 |
37 | for index in range(len(addresses) - 1):
38 | start = addresses[index]
39 | end = addresses[index + 1]
40 | make_function(start, end)
41 |
42 | for item in fun_infos:
43 | set_name(item[0], item[1])
44 |
45 |
46 |
47 | print('Script finished!')
48 |
49 |
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | google {
4 | content {
5 | includeGroupByRegex("com\\.android.*")
6 | includeGroupByRegex("com\\.google.*")
7 | includeGroupByRegex("androidx.*")
8 | }
9 | }
10 | mavenCentral()
11 | gradlePluginPortal()
12 | }
13 | }
14 | dependencyResolutionManagement {
15 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
16 | repositories {
17 | google()
18 | mavenCentral()
19 | }
20 | }
21 |
22 | rootProject.name = "Ptrace-Il2cppDumper"
23 | include(":app")
24 |
--------------------------------------------------------------------------------