mirror of
https://github.com/XLabsProject/iw6x-client.git
synced 2023-08-02 15:02:12 +02:00
Import w3x base
This commit is contained in:
parent
914dcfa40a
commit
b33c7a7fbe
37
.gitmodules
vendored
37
.gitmodules
vendored
@ -1,36 +1,19 @@
|
||||
[submodule "deps/libtommath"]
|
||||
path = deps/libtommath
|
||||
url = https://github.com/libtom/libtommath.git
|
||||
branch = develop
|
||||
[submodule "deps/libtomcrypt"]
|
||||
path = deps/libtomcrypt
|
||||
url = https://github.com/libtom/libtomcrypt.git
|
||||
branch = develop
|
||||
[submodule "deps/zlib"]
|
||||
path = deps/zlib
|
||||
url = https://github.com/madler/zlib.git
|
||||
branch = develop
|
||||
[submodule "deps/HDiffPatch"]
|
||||
path = deps/HDiffPatch
|
||||
url = https://github.com/sisong/HDiffPatch.git
|
||||
branch = master
|
||||
[submodule "deps/GSL"]
|
||||
path = deps/GSL
|
||||
url = https://github.com/Microsoft/GSL.git
|
||||
[submodule "deps/discord-rpc"]
|
||||
path = deps/discord-rpc
|
||||
url = https://github.com/discordapp/discord-rpc.git
|
||||
[submodule "deps/asmjit"]
|
||||
path = deps/asmjit
|
||||
url = https://github.com/asmjit/asmjit.git
|
||||
[submodule "deps/rapidjson"]
|
||||
path = deps/rapidjson
|
||||
url = https://github.com/Tencent/rapidjson.git
|
||||
[submodule "deps/udis86"]
|
||||
path = deps/udis86
|
||||
url = https://github.com/vmt/udis86.git
|
||||
[submodule "deps/ChaiScript"]
|
||||
path = deps/ChaiScript
|
||||
url = https://github.com/ChaiScript/ChaiScript.git
|
||||
branch = master
|
||||
[submodule "deps/zstd"]
|
||||
path = deps/zstd
|
||||
url = https://github.com/facebook/zstd.git
|
||||
branch = dev
|
||||
[submodule "deps/protobuf"]
|
||||
path = deps/protobuf
|
||||
url = https://github.com/google/protobuf.git
|
||||
branch = 3.12.x
|
||||
[submodule "deps/minhook"]
|
||||
path = deps/minhook
|
||||
url = https://github.com/TsudaKageyu/minhook.git
|
674
LICENSE
Normal file
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
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:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
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
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
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
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
1
deps/GSL
vendored
Submodule
1
deps/GSL
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 6aa755e9ce66a389b00bc6b591ce24541650d9f1
|
1
deps/asmjit
vendored
Submodule
1
deps/asmjit
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 8f25116f2bea8f5e0604dae867be817e3f12bac1
|
5946
deps/extra/udis86/libudis86/itab.c
vendored
Normal file
5946
deps/extra/udis86/libudis86/itab.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
939
deps/extra/udis86/libudis86/itab.h
vendored
Normal file
939
deps/extra/udis86/libudis86/itab.h
vendored
Normal file
@ -0,0 +1,939 @@
|
||||
#ifndef UD_ITAB_H
|
||||
#define UD_ITAB_H
|
||||
|
||||
/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */
|
||||
|
||||
/* ud_table_type -- lookup table types (see decode.c) */
|
||||
enum ud_table_type {
|
||||
UD_TAB__OPC_VEX,
|
||||
UD_TAB__OPC_TABLE,
|
||||
UD_TAB__OPC_X87,
|
||||
UD_TAB__OPC_MOD,
|
||||
UD_TAB__OPC_RM,
|
||||
UD_TAB__OPC_OSIZE,
|
||||
UD_TAB__OPC_MODE,
|
||||
UD_TAB__OPC_VEX_L,
|
||||
UD_TAB__OPC_3DNOW,
|
||||
UD_TAB__OPC_REG,
|
||||
UD_TAB__OPC_ASIZE,
|
||||
UD_TAB__OPC_VEX_W,
|
||||
UD_TAB__OPC_SSE,
|
||||
UD_TAB__OPC_VENDOR
|
||||
};
|
||||
|
||||
/* ud_mnemonic -- mnemonic constants */
|
||||
enum ud_mnemonic_code {
|
||||
UD_Iaaa,
|
||||
UD_Iaad,
|
||||
UD_Iaam,
|
||||
UD_Iaas,
|
||||
UD_Iadc,
|
||||
UD_Iadd,
|
||||
UD_Iaddpd,
|
||||
UD_Iaddps,
|
||||
UD_Iaddsd,
|
||||
UD_Iaddss,
|
||||
UD_Iaddsubpd,
|
||||
UD_Iaddsubps,
|
||||
UD_Iaesdec,
|
||||
UD_Iaesdeclast,
|
||||
UD_Iaesenc,
|
||||
UD_Iaesenclast,
|
||||
UD_Iaesimc,
|
||||
UD_Iaeskeygenassist,
|
||||
UD_Iand,
|
||||
UD_Iandnpd,
|
||||
UD_Iandnps,
|
||||
UD_Iandpd,
|
||||
UD_Iandps,
|
||||
UD_Iarpl,
|
||||
UD_Iblendpd,
|
||||
UD_Iblendps,
|
||||
UD_Iblendvpd,
|
||||
UD_Iblendvps,
|
||||
UD_Ibound,
|
||||
UD_Ibsf,
|
||||
UD_Ibsr,
|
||||
UD_Ibswap,
|
||||
UD_Ibt,
|
||||
UD_Ibtc,
|
||||
UD_Ibtr,
|
||||
UD_Ibts,
|
||||
UD_Icall,
|
||||
UD_Icbw,
|
||||
UD_Icdq,
|
||||
UD_Icdqe,
|
||||
UD_Iclc,
|
||||
UD_Icld,
|
||||
UD_Iclflush,
|
||||
UD_Iclgi,
|
||||
UD_Icli,
|
||||
UD_Iclts,
|
||||
UD_Icmc,
|
||||
UD_Icmova,
|
||||
UD_Icmovae,
|
||||
UD_Icmovb,
|
||||
UD_Icmovbe,
|
||||
UD_Icmovg,
|
||||
UD_Icmovge,
|
||||
UD_Icmovl,
|
||||
UD_Icmovle,
|
||||
UD_Icmovno,
|
||||
UD_Icmovnp,
|
||||
UD_Icmovns,
|
||||
UD_Icmovnz,
|
||||
UD_Icmovo,
|
||||
UD_Icmovp,
|
||||
UD_Icmovs,
|
||||
UD_Icmovz,
|
||||
UD_Icmp,
|
||||
UD_Icmppd,
|
||||
UD_Icmpps,
|
||||
UD_Icmpsb,
|
||||
UD_Icmpsd,
|
||||
UD_Icmpsq,
|
||||
UD_Icmpss,
|
||||
UD_Icmpsw,
|
||||
UD_Icmpxchg,
|
||||
UD_Icmpxchg16b,
|
||||
UD_Icmpxchg8b,
|
||||
UD_Icomisd,
|
||||
UD_Icomiss,
|
||||
UD_Icpuid,
|
||||
UD_Icqo,
|
||||
UD_Icrc32,
|
||||
UD_Icvtdq2pd,
|
||||
UD_Icvtdq2ps,
|
||||
UD_Icvtpd2dq,
|
||||
UD_Icvtpd2pi,
|
||||
UD_Icvtpd2ps,
|
||||
UD_Icvtpi2pd,
|
||||
UD_Icvtpi2ps,
|
||||
UD_Icvtps2dq,
|
||||
UD_Icvtps2pd,
|
||||
UD_Icvtps2pi,
|
||||
UD_Icvtsd2si,
|
||||
UD_Icvtsd2ss,
|
||||
UD_Icvtsi2sd,
|
||||
UD_Icvtsi2ss,
|
||||
UD_Icvtss2sd,
|
||||
UD_Icvtss2si,
|
||||
UD_Icvttpd2dq,
|
||||
UD_Icvttpd2pi,
|
||||
UD_Icvttps2dq,
|
||||
UD_Icvttps2pi,
|
||||
UD_Icvttsd2si,
|
||||
UD_Icvttss2si,
|
||||
UD_Icwd,
|
||||
UD_Icwde,
|
||||
UD_Idaa,
|
||||
UD_Idas,
|
||||
UD_Idec,
|
||||
UD_Idiv,
|
||||
UD_Idivpd,
|
||||
UD_Idivps,
|
||||
UD_Idivsd,
|
||||
UD_Idivss,
|
||||
UD_Idppd,
|
||||
UD_Idpps,
|
||||
UD_Iemms,
|
||||
UD_Ienter,
|
||||
UD_Iextractps,
|
||||
UD_If2xm1,
|
||||
UD_Ifabs,
|
||||
UD_Ifadd,
|
||||
UD_Ifaddp,
|
||||
UD_Ifbld,
|
||||
UD_Ifbstp,
|
||||
UD_Ifchs,
|
||||
UD_Ifclex,
|
||||
UD_Ifcmovb,
|
||||
UD_Ifcmovbe,
|
||||
UD_Ifcmove,
|
||||
UD_Ifcmovnb,
|
||||
UD_Ifcmovnbe,
|
||||
UD_Ifcmovne,
|
||||
UD_Ifcmovnu,
|
||||
UD_Ifcmovu,
|
||||
UD_Ifcom,
|
||||
UD_Ifcom2,
|
||||
UD_Ifcomi,
|
||||
UD_Ifcomip,
|
||||
UD_Ifcomp,
|
||||
UD_Ifcomp3,
|
||||
UD_Ifcomp5,
|
||||
UD_Ifcompp,
|
||||
UD_Ifcos,
|
||||
UD_Ifdecstp,
|
||||
UD_Ifdiv,
|
||||
UD_Ifdivp,
|
||||
UD_Ifdivr,
|
||||
UD_Ifdivrp,
|
||||
UD_Ifemms,
|
||||
UD_Iffree,
|
||||
UD_Iffreep,
|
||||
UD_Ifiadd,
|
||||
UD_Ificom,
|
||||
UD_Ificomp,
|
||||
UD_Ifidiv,
|
||||
UD_Ifidivr,
|
||||
UD_Ifild,
|
||||
UD_Ifimul,
|
||||
UD_Ifincstp,
|
||||
UD_Ifist,
|
||||
UD_Ifistp,
|
||||
UD_Ifisttp,
|
||||
UD_Ifisub,
|
||||
UD_Ifisubr,
|
||||
UD_Ifld,
|
||||
UD_Ifld1,
|
||||
UD_Ifldcw,
|
||||
UD_Ifldenv,
|
||||
UD_Ifldl2e,
|
||||
UD_Ifldl2t,
|
||||
UD_Ifldlg2,
|
||||
UD_Ifldln2,
|
||||
UD_Ifldpi,
|
||||
UD_Ifldz,
|
||||
UD_Ifmul,
|
||||
UD_Ifmulp,
|
||||
UD_Ifndisi,
|
||||
UD_Ifneni,
|
||||
UD_Ifninit,
|
||||
UD_Ifnop,
|
||||
UD_Ifnsave,
|
||||
UD_Ifnsetpm,
|
||||
UD_Ifnstcw,
|
||||
UD_Ifnstenv,
|
||||
UD_Ifnstsw,
|
||||
UD_Ifpatan,
|
||||
UD_Ifprem,
|
||||
UD_Ifprem1,
|
||||
UD_Ifptan,
|
||||
UD_Ifrndint,
|
||||
UD_Ifrstor,
|
||||
UD_Ifrstpm,
|
||||
UD_Ifscale,
|
||||
UD_Ifsin,
|
||||
UD_Ifsincos,
|
||||
UD_Ifsqrt,
|
||||
UD_Ifst,
|
||||
UD_Ifstp,
|
||||
UD_Ifstp1,
|
||||
UD_Ifstp8,
|
||||
UD_Ifstp9,
|
||||
UD_Ifsub,
|
||||
UD_Ifsubp,
|
||||
UD_Ifsubr,
|
||||
UD_Ifsubrp,
|
||||
UD_Iftst,
|
||||
UD_Ifucom,
|
||||
UD_Ifucomi,
|
||||
UD_Ifucomip,
|
||||
UD_Ifucomp,
|
||||
UD_Ifucompp,
|
||||
UD_Ifxam,
|
||||
UD_Ifxch,
|
||||
UD_Ifxch4,
|
||||
UD_Ifxch7,
|
||||
UD_Ifxrstor,
|
||||
UD_Ifxsave,
|
||||
UD_Ifxtract,
|
||||
UD_Ifyl2x,
|
||||
UD_Ifyl2xp1,
|
||||
UD_Igetsec,
|
||||
UD_Ihaddpd,
|
||||
UD_Ihaddps,
|
||||
UD_Ihlt,
|
||||
UD_Ihsubpd,
|
||||
UD_Ihsubps,
|
||||
UD_Iidiv,
|
||||
UD_Iimul,
|
||||
UD_Iin,
|
||||
UD_Iinc,
|
||||
UD_Iinsb,
|
||||
UD_Iinsd,
|
||||
UD_Iinsertps,
|
||||
UD_Iinsw,
|
||||
UD_Iint,
|
||||
UD_Iint1,
|
||||
UD_Iint3,
|
||||
UD_Iinto,
|
||||
UD_Iinvd,
|
||||
UD_Iinvept,
|
||||
UD_Iinvlpg,
|
||||
UD_Iinvlpga,
|
||||
UD_Iinvvpid,
|
||||
UD_Iiretd,
|
||||
UD_Iiretq,
|
||||
UD_Iiretw,
|
||||
UD_Ija,
|
||||
UD_Ijae,
|
||||
UD_Ijb,
|
||||
UD_Ijbe,
|
||||
UD_Ijcxz,
|
||||
UD_Ijecxz,
|
||||
UD_Ijg,
|
||||
UD_Ijge,
|
||||
UD_Ijl,
|
||||
UD_Ijle,
|
||||
UD_Ijmp,
|
||||
UD_Ijno,
|
||||
UD_Ijnp,
|
||||
UD_Ijns,
|
||||
UD_Ijnz,
|
||||
UD_Ijo,
|
||||
UD_Ijp,
|
||||
UD_Ijrcxz,
|
||||
UD_Ijs,
|
||||
UD_Ijz,
|
||||
UD_Ilahf,
|
||||
UD_Ilar,
|
||||
UD_Ilddqu,
|
||||
UD_Ildmxcsr,
|
||||
UD_Ilds,
|
||||
UD_Ilea,
|
||||
UD_Ileave,
|
||||
UD_Iles,
|
||||
UD_Ilfence,
|
||||
UD_Ilfs,
|
||||
UD_Ilgdt,
|
||||
UD_Ilgs,
|
||||
UD_Ilidt,
|
||||
UD_Illdt,
|
||||
UD_Ilmsw,
|
||||
UD_Ilock,
|
||||
UD_Ilodsb,
|
||||
UD_Ilodsd,
|
||||
UD_Ilodsq,
|
||||
UD_Ilodsw,
|
||||
UD_Iloop,
|
||||
UD_Iloope,
|
||||
UD_Iloopne,
|
||||
UD_Ilsl,
|
||||
UD_Ilss,
|
||||
UD_Iltr,
|
||||
UD_Imaskmovdqu,
|
||||
UD_Imaskmovq,
|
||||
UD_Imaxpd,
|
||||
UD_Imaxps,
|
||||
UD_Imaxsd,
|
||||
UD_Imaxss,
|
||||
UD_Imfence,
|
||||
UD_Iminpd,
|
||||
UD_Iminps,
|
||||
UD_Iminsd,
|
||||
UD_Iminss,
|
||||
UD_Imonitor,
|
||||
UD_Imontmul,
|
||||
UD_Imov,
|
||||
UD_Imovapd,
|
||||
UD_Imovaps,
|
||||
UD_Imovbe,
|
||||
UD_Imovd,
|
||||
UD_Imovddup,
|
||||
UD_Imovdq2q,
|
||||
UD_Imovdqa,
|
||||
UD_Imovdqu,
|
||||
UD_Imovhlps,
|
||||
UD_Imovhpd,
|
||||
UD_Imovhps,
|
||||
UD_Imovlhps,
|
||||
UD_Imovlpd,
|
||||
UD_Imovlps,
|
||||
UD_Imovmskpd,
|
||||
UD_Imovmskps,
|
||||
UD_Imovntdq,
|
||||
UD_Imovntdqa,
|
||||
UD_Imovnti,
|
||||
UD_Imovntpd,
|
||||
UD_Imovntps,
|
||||
UD_Imovntq,
|
||||
UD_Imovq,
|
||||
UD_Imovq2dq,
|
||||
UD_Imovsb,
|
||||
UD_Imovsd,
|
||||
UD_Imovshdup,
|
||||
UD_Imovsldup,
|
||||
UD_Imovsq,
|
||||
UD_Imovss,
|
||||
UD_Imovsw,
|
||||
UD_Imovsx,
|
||||
UD_Imovsxd,
|
||||
UD_Imovupd,
|
||||
UD_Imovups,
|
||||
UD_Imovzx,
|
||||
UD_Impsadbw,
|
||||
UD_Imul,
|
||||
UD_Imulpd,
|
||||
UD_Imulps,
|
||||
UD_Imulsd,
|
||||
UD_Imulss,
|
||||
UD_Imwait,
|
||||
UD_Ineg,
|
||||
UD_Inop,
|
||||
UD_Inot,
|
||||
UD_Ior,
|
||||
UD_Iorpd,
|
||||
UD_Iorps,
|
||||
UD_Iout,
|
||||
UD_Ioutsb,
|
||||
UD_Ioutsd,
|
||||
UD_Ioutsw,
|
||||
UD_Ipabsb,
|
||||
UD_Ipabsd,
|
||||
UD_Ipabsw,
|
||||
UD_Ipackssdw,
|
||||
UD_Ipacksswb,
|
||||
UD_Ipackusdw,
|
||||
UD_Ipackuswb,
|
||||
UD_Ipaddb,
|
||||
UD_Ipaddd,
|
||||
UD_Ipaddq,
|
||||
UD_Ipaddsb,
|
||||
UD_Ipaddsw,
|
||||
UD_Ipaddusb,
|
||||
UD_Ipaddusw,
|
||||
UD_Ipaddw,
|
||||
UD_Ipalignr,
|
||||
UD_Ipand,
|
||||
UD_Ipandn,
|
||||
UD_Ipavgb,
|
||||
UD_Ipavgusb,
|
||||
UD_Ipavgw,
|
||||
UD_Ipblendvb,
|
||||
UD_Ipblendw,
|
||||
UD_Ipclmulqdq,
|
||||
UD_Ipcmpeqb,
|
||||
UD_Ipcmpeqd,
|
||||
UD_Ipcmpeqq,
|
||||
UD_Ipcmpeqw,
|
||||
UD_Ipcmpestri,
|
||||
UD_Ipcmpestrm,
|
||||
UD_Ipcmpgtb,
|
||||
UD_Ipcmpgtd,
|
||||
UD_Ipcmpgtq,
|
||||
UD_Ipcmpgtw,
|
||||
UD_Ipcmpistri,
|
||||
UD_Ipcmpistrm,
|
||||
UD_Ipextrb,
|
||||
UD_Ipextrd,
|
||||
UD_Ipextrq,
|
||||
UD_Ipextrw,
|
||||
UD_Ipf2id,
|
||||
UD_Ipf2iw,
|
||||
UD_Ipfacc,
|
||||
UD_Ipfadd,
|
||||
UD_Ipfcmpeq,
|
||||
UD_Ipfcmpge,
|
||||
UD_Ipfcmpgt,
|
||||
UD_Ipfmax,
|
||||
UD_Ipfmin,
|
||||
UD_Ipfmul,
|
||||
UD_Ipfnacc,
|
||||
UD_Ipfpnacc,
|
||||
UD_Ipfrcp,
|
||||
UD_Ipfrcpit1,
|
||||
UD_Ipfrcpit2,
|
||||
UD_Ipfrsqit1,
|
||||
UD_Ipfrsqrt,
|
||||
UD_Ipfsub,
|
||||
UD_Ipfsubr,
|
||||
UD_Iphaddd,
|
||||
UD_Iphaddsw,
|
||||
UD_Iphaddw,
|
||||
UD_Iphminposuw,
|
||||
UD_Iphsubd,
|
||||
UD_Iphsubsw,
|
||||
UD_Iphsubw,
|
||||
UD_Ipi2fd,
|
||||
UD_Ipi2fw,
|
||||
UD_Ipinsrb,
|
||||
UD_Ipinsrd,
|
||||
UD_Ipinsrq,
|
||||
UD_Ipinsrw,
|
||||
UD_Ipmaddubsw,
|
||||
UD_Ipmaddwd,
|
||||
UD_Ipmaxsb,
|
||||
UD_Ipmaxsd,
|
||||
UD_Ipmaxsw,
|
||||
UD_Ipmaxub,
|
||||
UD_Ipmaxud,
|
||||
UD_Ipmaxuw,
|
||||
UD_Ipminsb,
|
||||
UD_Ipminsd,
|
||||
UD_Ipminsw,
|
||||
UD_Ipminub,
|
||||
UD_Ipminud,
|
||||
UD_Ipminuw,
|
||||
UD_Ipmovmskb,
|
||||
UD_Ipmovsxbd,
|
||||
UD_Ipmovsxbq,
|
||||
UD_Ipmovsxbw,
|
||||
UD_Ipmovsxdq,
|
||||
UD_Ipmovsxwd,
|
||||
UD_Ipmovsxwq,
|
||||
UD_Ipmovzxbd,
|
||||
UD_Ipmovzxbq,
|
||||
UD_Ipmovzxbw,
|
||||
UD_Ipmovzxdq,
|
||||
UD_Ipmovzxwd,
|
||||
UD_Ipmovzxwq,
|
||||
UD_Ipmuldq,
|
||||
UD_Ipmulhrsw,
|
||||
UD_Ipmulhrw,
|
||||
UD_Ipmulhuw,
|
||||
UD_Ipmulhw,
|
||||
UD_Ipmulld,
|
||||
UD_Ipmullw,
|
||||
UD_Ipmuludq,
|
||||
UD_Ipop,
|
||||
UD_Ipopa,
|
||||
UD_Ipopad,
|
||||
UD_Ipopcnt,
|
||||
UD_Ipopfd,
|
||||
UD_Ipopfq,
|
||||
UD_Ipopfw,
|
||||
UD_Ipor,
|
||||
UD_Iprefetch,
|
||||
UD_Iprefetchnta,
|
||||
UD_Iprefetcht0,
|
||||
UD_Iprefetcht1,
|
||||
UD_Iprefetcht2,
|
||||
UD_Ipsadbw,
|
||||
UD_Ipshufb,
|
||||
UD_Ipshufd,
|
||||
UD_Ipshufhw,
|
||||
UD_Ipshuflw,
|
||||
UD_Ipshufw,
|
||||
UD_Ipsignb,
|
||||
UD_Ipsignd,
|
||||
UD_Ipsignw,
|
||||
UD_Ipslld,
|
||||
UD_Ipslldq,
|
||||
UD_Ipsllq,
|
||||
UD_Ipsllw,
|
||||
UD_Ipsrad,
|
||||
UD_Ipsraw,
|
||||
UD_Ipsrld,
|
||||
UD_Ipsrldq,
|
||||
UD_Ipsrlq,
|
||||
UD_Ipsrlw,
|
||||
UD_Ipsubb,
|
||||
UD_Ipsubd,
|
||||
UD_Ipsubq,
|
||||
UD_Ipsubsb,
|
||||
UD_Ipsubsw,
|
||||
UD_Ipsubusb,
|
||||
UD_Ipsubusw,
|
||||
UD_Ipsubw,
|
||||
UD_Ipswapd,
|
||||
UD_Iptest,
|
||||
UD_Ipunpckhbw,
|
||||
UD_Ipunpckhdq,
|
||||
UD_Ipunpckhqdq,
|
||||
UD_Ipunpckhwd,
|
||||
UD_Ipunpcklbw,
|
||||
UD_Ipunpckldq,
|
||||
UD_Ipunpcklqdq,
|
||||
UD_Ipunpcklwd,
|
||||
UD_Ipush,
|
||||
UD_Ipusha,
|
||||
UD_Ipushad,
|
||||
UD_Ipushfd,
|
||||
UD_Ipushfq,
|
||||
UD_Ipushfw,
|
||||
UD_Ipxor,
|
||||
UD_Ircl,
|
||||
UD_Ircpps,
|
||||
UD_Ircpss,
|
||||
UD_Ircr,
|
||||
UD_Irdmsr,
|
||||
UD_Irdpmc,
|
||||
UD_Irdrand,
|
||||
UD_Irdtsc,
|
||||
UD_Irdtscp,
|
||||
UD_Irep,
|
||||
UD_Irepne,
|
||||
UD_Iret,
|
||||
UD_Iretf,
|
||||
UD_Irol,
|
||||
UD_Iror,
|
||||
UD_Iroundpd,
|
||||
UD_Iroundps,
|
||||
UD_Iroundsd,
|
||||
UD_Iroundss,
|
||||
UD_Irsm,
|
||||
UD_Irsqrtps,
|
||||
UD_Irsqrtss,
|
||||
UD_Isahf,
|
||||
UD_Isalc,
|
||||
UD_Isar,
|
||||
UD_Isbb,
|
||||
UD_Iscasb,
|
||||
UD_Iscasd,
|
||||
UD_Iscasq,
|
||||
UD_Iscasw,
|
||||
UD_Iseta,
|
||||
UD_Isetae,
|
||||
UD_Isetb,
|
||||
UD_Isetbe,
|
||||
UD_Isetg,
|
||||
UD_Isetge,
|
||||
UD_Isetl,
|
||||
UD_Isetle,
|
||||
UD_Isetno,
|
||||
UD_Isetnp,
|
||||
UD_Isetns,
|
||||
UD_Isetnz,
|
||||
UD_Iseto,
|
||||
UD_Isetp,
|
||||
UD_Isets,
|
||||
UD_Isetz,
|
||||
UD_Isfence,
|
||||
UD_Isgdt,
|
||||
UD_Ishl,
|
||||
UD_Ishld,
|
||||
UD_Ishr,
|
||||
UD_Ishrd,
|
||||
UD_Ishufpd,
|
||||
UD_Ishufps,
|
||||
UD_Isidt,
|
||||
UD_Iskinit,
|
||||
UD_Isldt,
|
||||
UD_Ismsw,
|
||||
UD_Isqrtpd,
|
||||
UD_Isqrtps,
|
||||
UD_Isqrtsd,
|
||||
UD_Isqrtss,
|
||||
UD_Istc,
|
||||
UD_Istd,
|
||||
UD_Istgi,
|
||||
UD_Isti,
|
||||
UD_Istmxcsr,
|
||||
UD_Istosb,
|
||||
UD_Istosd,
|
||||
UD_Istosq,
|
||||
UD_Istosw,
|
||||
UD_Istr,
|
||||
UD_Isub,
|
||||
UD_Isubpd,
|
||||
UD_Isubps,
|
||||
UD_Isubsd,
|
||||
UD_Isubss,
|
||||
UD_Iswapgs,
|
||||
UD_Isyscall,
|
||||
UD_Isysenter,
|
||||
UD_Isysexit,
|
||||
UD_Isysret,
|
||||
UD_Itest,
|
||||
UD_Iucomisd,
|
||||
UD_Iucomiss,
|
||||
UD_Iud2,
|
||||
UD_Iunpckhpd,
|
||||
UD_Iunpckhps,
|
||||
UD_Iunpcklpd,
|
||||
UD_Iunpcklps,
|
||||
UD_Ivaddpd,
|
||||
UD_Ivaddps,
|
||||
UD_Ivaddsd,
|
||||
UD_Ivaddss,
|
||||
UD_Ivaddsubpd,
|
||||
UD_Ivaddsubps,
|
||||
UD_Ivaesdec,
|
||||
UD_Ivaesdeclast,
|
||||
UD_Ivaesenc,
|
||||
UD_Ivaesenclast,
|
||||
UD_Ivaesimc,
|
||||
UD_Ivaeskeygenassist,
|
||||
UD_Ivandnpd,
|
||||
UD_Ivandnps,
|
||||
UD_Ivandpd,
|
||||
UD_Ivandps,
|
||||
UD_Ivblendpd,
|
||||
UD_Ivblendps,
|
||||
UD_Ivblendvpd,
|
||||
UD_Ivblendvps,
|
||||
UD_Ivbroadcastsd,
|
||||
UD_Ivbroadcastss,
|
||||
UD_Ivcmppd,
|
||||
UD_Ivcmpps,
|
||||
UD_Ivcmpsd,
|
||||
UD_Ivcmpss,
|
||||
UD_Ivcomisd,
|
||||
UD_Ivcomiss,
|
||||
UD_Ivcvtdq2pd,
|
||||
UD_Ivcvtdq2ps,
|
||||
UD_Ivcvtpd2dq,
|
||||
UD_Ivcvtpd2ps,
|
||||
UD_Ivcvtps2dq,
|
||||
UD_Ivcvtps2pd,
|
||||
UD_Ivcvtsd2si,
|
||||
UD_Ivcvtsd2ss,
|
||||
UD_Ivcvtsi2sd,
|
||||
UD_Ivcvtsi2ss,
|
||||
UD_Ivcvtss2sd,
|
||||
UD_Ivcvtss2si,
|
||||
UD_Ivcvttpd2dq,
|
||||
UD_Ivcvttps2dq,
|
||||
UD_Ivcvttsd2si,
|
||||
UD_Ivcvttss2si,
|
||||
UD_Ivdivpd,
|
||||
UD_Ivdivps,
|
||||
UD_Ivdivsd,
|
||||
UD_Ivdivss,
|
||||
UD_Ivdppd,
|
||||
UD_Ivdpps,
|
||||
UD_Iverr,
|
||||
UD_Iverw,
|
||||
UD_Ivextractf128,
|
||||
UD_Ivextractps,
|
||||
UD_Ivhaddpd,
|
||||
UD_Ivhaddps,
|
||||
UD_Ivhsubpd,
|
||||
UD_Ivhsubps,
|
||||
UD_Ivinsertf128,
|
||||
UD_Ivinsertps,
|
||||
UD_Ivlddqu,
|
||||
UD_Ivmaskmovdqu,
|
||||
UD_Ivmaskmovpd,
|
||||
UD_Ivmaskmovps,
|
||||
UD_Ivmaxpd,
|
||||
UD_Ivmaxps,
|
||||
UD_Ivmaxsd,
|
||||
UD_Ivmaxss,
|
||||
UD_Ivmcall,
|
||||
UD_Ivmclear,
|
||||
UD_Ivminpd,
|
||||
UD_Ivminps,
|
||||
UD_Ivminsd,
|
||||
UD_Ivminss,
|
||||
UD_Ivmlaunch,
|
||||
UD_Ivmload,
|
||||
UD_Ivmmcall,
|
||||
UD_Ivmovapd,
|
||||
UD_Ivmovaps,
|
||||
UD_Ivmovd,
|
||||
UD_Ivmovddup,
|
||||
UD_Ivmovdqa,
|
||||
UD_Ivmovdqu,
|
||||
UD_Ivmovhlps,
|
||||
UD_Ivmovhpd,
|
||||
UD_Ivmovhps,
|
||||
UD_Ivmovlhps,
|
||||
UD_Ivmovlpd,
|
||||
UD_Ivmovlps,
|
||||
UD_Ivmovmskpd,
|
||||
UD_Ivmovmskps,
|
||||
UD_Ivmovntdq,
|
||||
UD_Ivmovntdqa,
|
||||
UD_Ivmovntpd,
|
||||
UD_Ivmovntps,
|
||||
UD_Ivmovq,
|
||||
UD_Ivmovsd,
|
||||
UD_Ivmovshdup,
|
||||
UD_Ivmovsldup,
|
||||
UD_Ivmovss,
|
||||
UD_Ivmovupd,
|
||||
UD_Ivmovups,
|
||||
UD_Ivmpsadbw,
|
||||
UD_Ivmptrld,
|
||||
UD_Ivmptrst,
|
||||
UD_Ivmread,
|
||||
UD_Ivmresume,
|
||||
UD_Ivmrun,
|
||||
UD_Ivmsave,
|
||||
UD_Ivmulpd,
|
||||
UD_Ivmulps,
|
||||
UD_Ivmulsd,
|
||||
UD_Ivmulss,
|
||||
UD_Ivmwrite,
|
||||
UD_Ivmxoff,
|
||||
UD_Ivmxon,
|
||||
UD_Ivorpd,
|
||||
UD_Ivorps,
|
||||
UD_Ivpabsb,
|
||||
UD_Ivpabsd,
|
||||
UD_Ivpabsw,
|
||||
UD_Ivpackssdw,
|
||||
UD_Ivpacksswb,
|
||||
UD_Ivpackusdw,
|
||||
UD_Ivpackuswb,
|
||||
UD_Ivpaddb,
|
||||
UD_Ivpaddd,
|
||||
UD_Ivpaddq,
|
||||
UD_Ivpaddsb,
|
||||
UD_Ivpaddsw,
|
||||
UD_Ivpaddusb,
|
||||
UD_Ivpaddusw,
|
||||
UD_Ivpaddw,
|
||||
UD_Ivpalignr,
|
||||
UD_Ivpand,
|
||||
UD_Ivpandn,
|
||||
UD_Ivpavgb,
|
||||
UD_Ivpavgw,
|
||||
UD_Ivpblendvb,
|
||||
UD_Ivpblendw,
|
||||
UD_Ivpclmulqdq,
|
||||
UD_Ivpcmpeqb,
|
||||
UD_Ivpcmpeqd,
|
||||
UD_Ivpcmpeqq,
|
||||
UD_Ivpcmpeqw,
|
||||
UD_Ivpcmpestri,
|
||||
UD_Ivpcmpestrm,
|
||||
UD_Ivpcmpgtb,
|
||||
UD_Ivpcmpgtd,
|
||||
UD_Ivpcmpgtq,
|
||||
UD_Ivpcmpgtw,
|
||||
UD_Ivpcmpistri,
|
||||
UD_Ivpcmpistrm,
|
||||
UD_Ivperm2f128,
|
||||
UD_Ivpermilpd,
|
||||
UD_Ivpermilps,
|
||||
UD_Ivpextrb,
|
||||
UD_Ivpextrd,
|
||||
UD_Ivpextrq,
|
||||
UD_Ivpextrw,
|
||||
UD_Ivphaddd,
|
||||
UD_Ivphaddsw,
|
||||
UD_Ivphaddw,
|
||||
UD_Ivphminposuw,
|
||||
UD_Ivphsubd,
|
||||
UD_Ivphsubsw,
|
||||
UD_Ivphsubw,
|
||||
UD_Ivpinsrb,
|
||||
UD_Ivpinsrd,
|
||||
UD_Ivpinsrq,
|
||||
UD_Ivpinsrw,
|
||||
UD_Ivpmaddubsw,
|
||||
UD_Ivpmaddwd,
|
||||
UD_Ivpmaxsb,
|
||||
UD_Ivpmaxsd,
|
||||
UD_Ivpmaxsw,
|
||||
UD_Ivpmaxub,
|
||||
UD_Ivpmaxud,
|
||||
UD_Ivpmaxuw,
|
||||
UD_Ivpminsb,
|
||||
UD_Ivpminsd,
|
||||
UD_Ivpminsw,
|
||||
UD_Ivpminub,
|
||||
UD_Ivpminud,
|
||||
UD_Ivpminuw,
|
||||
UD_Ivpmovmskb,
|
||||
UD_Ivpmovsxbd,
|
||||
UD_Ivpmovsxbq,
|
||||
UD_Ivpmovsxbw,
|
||||
UD_Ivpmovsxwd,
|
||||
UD_Ivpmovsxwq,
|
||||
UD_Ivpmovzxbd,
|
||||
UD_Ivpmovzxbq,
|
||||
UD_Ivpmovzxbw,
|
||||
UD_Ivpmovzxdq,
|
||||
UD_Ivpmovzxwd,
|
||||
UD_Ivpmovzxwq,
|
||||
UD_Ivpmuldq,
|
||||
UD_Ivpmulhrsw,
|
||||
UD_Ivpmulhuw,
|
||||
UD_Ivpmulhw,
|
||||
UD_Ivpmulld,
|
||||
UD_Ivpmullw,
|
||||
UD_Ivpor,
|
||||
UD_Ivpsadbw,
|
||||
UD_Ivpshufb,
|
||||
UD_Ivpshufd,
|
||||
UD_Ivpshufhw,
|
||||
UD_Ivpshuflw,
|
||||
UD_Ivpsignb,
|
||||
UD_Ivpsignd,
|
||||
UD_Ivpsignw,
|
||||
UD_Ivpslld,
|
||||
UD_Ivpslldq,
|
||||
UD_Ivpsllq,
|
||||
UD_Ivpsllw,
|
||||
UD_Ivpsrad,
|
||||
UD_Ivpsraw,
|
||||
UD_Ivpsrld,
|
||||
UD_Ivpsrldq,
|
||||
UD_Ivpsrlq,
|
||||
UD_Ivpsrlw,
|
||||
UD_Ivpsubb,
|
||||
UD_Ivpsubd,
|
||||
UD_Ivpsubq,
|
||||
UD_Ivpsubsb,
|
||||
UD_Ivpsubsw,
|
||||
UD_Ivpsubusb,
|
||||
UD_Ivpsubusw,
|
||||
UD_Ivpsubw,
|
||||
UD_Ivptest,
|
||||
UD_Ivpunpckhbw,
|
||||
UD_Ivpunpckhdq,
|
||||
UD_Ivpunpckhqdq,
|
||||
UD_Ivpunpckhwd,
|
||||
UD_Ivpunpcklbw,
|
||||
UD_Ivpunpckldq,
|
||||
UD_Ivpunpcklqdq,
|
||||
UD_Ivpunpcklwd,
|
||||
UD_Ivpxor,
|
||||
UD_Ivrcpps,
|
||||
UD_Ivrcpss,
|
||||
UD_Ivroundpd,
|
||||
UD_Ivroundps,
|
||||
UD_Ivroundsd,
|
||||
UD_Ivroundss,
|
||||
UD_Ivrsqrtps,
|
||||
UD_Ivrsqrtss,
|
||||
UD_Ivshufpd,
|
||||
UD_Ivshufps,
|
||||
UD_Ivsqrtpd,
|
||||
UD_Ivsqrtps,
|
||||
UD_Ivsqrtsd,
|
||||
UD_Ivsqrtss,
|
||||
UD_Ivstmxcsr,
|
||||
UD_Ivsubpd,
|
||||
UD_Ivsubps,
|
||||
UD_Ivsubsd,
|
||||
UD_Ivsubss,
|
||||
UD_Ivtestpd,
|
||||
UD_Ivtestps,
|
||||
UD_Ivucomisd,
|
||||
UD_Ivucomiss,
|
||||
UD_Ivunpckhpd,
|
||||
UD_Ivunpckhps,
|
||||
UD_Ivunpcklpd,
|
||||
UD_Ivunpcklps,
|
||||
UD_Ivxorpd,
|
||||
UD_Ivxorps,
|
||||
UD_Ivzeroall,
|
||||
UD_Ivzeroupper,
|
||||
UD_Iwait,
|
||||
UD_Iwbinvd,
|
||||
UD_Iwrmsr,
|
||||
UD_Ixadd,
|
||||
UD_Ixchg,
|
||||
UD_Ixcryptcbc,
|
||||
UD_Ixcryptcfb,
|
||||
UD_Ixcryptctr,
|
||||
UD_Ixcryptecb,
|
||||
UD_Ixcryptofb,
|
||||
UD_Ixgetbv,
|
||||
UD_Ixlatb,
|
||||
UD_Ixor,
|
||||
UD_Ixorpd,
|
||||
UD_Ixorps,
|
||||
UD_Ixrstor,
|
||||
UD_Ixsave,
|
||||
UD_Ixsetbv,
|
||||
UD_Ixsha1,
|
||||
UD_Ixsha256,
|
||||
UD_Ixstore,
|
||||
UD_Iinvalid,
|
||||
UD_I3dnow,
|
||||
UD_Inone,
|
||||
UD_Idb,
|
||||
UD_Ipause,
|
||||
UD_MAX_MNEMONIC_CODE
|
||||
};
|
||||
|
||||
extern const char * ud_mnemonics_str[];
|
||||
|
||||
#endif /* UD_ITAB_H */
|
1
deps/minhook
vendored
Submodule
1
deps/minhook
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 8fda4f5481fed5797dc2651cd91e238e9b3928c6
|
34
deps/premake/asmjit.lua
vendored
Normal file
34
deps/premake/asmjit.lua
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
asmjit = {
|
||||
source = path.join(dependencies.basePath, "asmjit"),
|
||||
}
|
||||
|
||||
function asmjit.import()
|
||||
links { "asmjit" }
|
||||
asmjit.includes()
|
||||
end
|
||||
|
||||
function asmjit.includes()
|
||||
includedirs {
|
||||
path.join(asmjit.source, "src")
|
||||
}
|
||||
|
||||
defines {
|
||||
"ASMJIT_STATIC"
|
||||
}
|
||||
end
|
||||
|
||||
function asmjit.project()
|
||||
project "asmjit"
|
||||
language "C++"
|
||||
|
||||
asmjit.includes()
|
||||
|
||||
files {
|
||||
path.join(asmjit.source, "src/**.cpp"),
|
||||
}
|
||||
|
||||
warnings "Off"
|
||||
kind "StaticLib"
|
||||
end
|
||||
|
||||
table.insert(dependencies, asmjit)
|
19
deps/premake/gsl.lua
vendored
Normal file
19
deps/premake/gsl.lua
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
gsl = {
|
||||
source = path.join(dependencies.basePath, "GSL"),
|
||||
}
|
||||
|
||||
function gsl.import()
|
||||
gsl.includes()
|
||||
end
|
||||
|
||||
function gsl.includes()
|
||||
includedirs {
|
||||
path.join(gsl.source, "include")
|
||||
}
|
||||
end
|
||||
|
||||
function gsl.project()
|
||||
|
||||
end
|
||||
|
||||
table.insert(dependencies, gsl)
|
31
deps/premake/minhook.lua
vendored
Normal file
31
deps/premake/minhook.lua
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
minhook = {
|
||||
source = path.join(dependencies.basePath, "minhook"),
|
||||
}
|
||||
|
||||
function minhook.import()
|
||||
links { "minhook" }
|
||||
minhook.includes()
|
||||
end
|
||||
|
||||
function minhook.includes()
|
||||
includedirs {
|
||||
path.join(minhook.source, "include")
|
||||
}
|
||||
end
|
||||
|
||||
function minhook.project()
|
||||
project "minhook"
|
||||
language "C"
|
||||
|
||||
minhook.includes()
|
||||
|
||||
files {
|
||||
path.join(minhook.source, "src/**.h"),
|
||||
path.join(minhook.source, "src/**.c"),
|
||||
}
|
||||
|
||||
warnings "Off"
|
||||
kind "StaticLib"
|
||||
end
|
||||
|
||||
table.insert(dependencies, minhook)
|
55
deps/premake/nng.lua
vendored
Normal file
55
deps/premake/nng.lua
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
nng = {
|
||||
source = path.join(dependencies.basePath, "nng"),
|
||||
}
|
||||
|
||||
function nng.import()
|
||||
links {
|
||||
"nng"
|
||||
}
|
||||
|
||||
nng.includes()
|
||||
end
|
||||
|
||||
function nng.includes()
|
||||
includedirs {
|
||||
path.join(nng.source, "include"),
|
||||
}
|
||||
|
||||
defines {
|
||||
"NNG_PLATFORM_WINDOWS"
|
||||
}
|
||||
end
|
||||
|
||||
function nng.project()
|
||||
project "nng"
|
||||
language "C"
|
||||
|
||||
nng.includes()
|
||||
|
||||
includedirs {
|
||||
path.join(nng.source, "src"),
|
||||
}
|
||||
|
||||
files {
|
||||
path.join(nng.source, "src/**.c"),
|
||||
path.join(nng.source, "src/**.h"),
|
||||
}
|
||||
|
||||
removefiles {
|
||||
path.join(nng.source, "src/platform/posix/**"),
|
||||
path.join(nng.source, "src/**/*test.c"),
|
||||
path.join(nng.source, "src/compat/**"),
|
||||
path.join(nng.source, "src/transport/tls/**"),
|
||||
path.join(nng.source, "src/transport/zerotier/**"),
|
||||
path.join(nng.source, "src/supplemental/tls/**"),
|
||||
}
|
||||
|
||||
linkoptions {
|
||||
"-IGNORE:4006"
|
||||
}
|
||||
|
||||
warnings "Off"
|
||||
kind "StaticLib"
|
||||
end
|
||||
|
||||
table.insert(dependencies, nng)
|
19
deps/premake/nngpp.lua
vendored
Normal file
19
deps/premake/nngpp.lua
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
nngpp = {
|
||||
source = path.join(dependencies.basePath, "nngpp"),
|
||||
}
|
||||
|
||||
function nngpp.import()
|
||||
nngpp.includes()
|
||||
end
|
||||
|
||||
function nngpp.includes()
|
||||
includedirs {
|
||||
path.join(nngpp.source, "include"),
|
||||
}
|
||||
end
|
||||
|
||||
function nngpp.project()
|
||||
|
||||
end
|
||||
|
||||
table.insert(dependencies, nngpp)
|
60
deps/premake/protobuf.lua
vendored
Normal file
60
deps/premake/protobuf.lua
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
protobuf = {
|
||||
source = path.join(dependencies.basePath, "protobuf"),
|
||||
}
|
||||
|
||||
function protobuf.import()
|
||||
links {
|
||||
"protobuf"
|
||||
}
|
||||
|
||||
protobuf.includes()
|
||||
end
|
||||
|
||||
function protobuf.includes()
|
||||
includedirs {
|
||||
path.join(protobuf.source, "src"),
|
||||
}
|
||||
end
|
||||
|
||||
function protobuf.project()
|
||||
project "protobuf"
|
||||
language "C++"
|
||||
|
||||
protobuf.includes()
|
||||
|
||||
files {
|
||||
path.join(protobuf.source, "src/**.cc"),
|
||||
"./src/**.proto",
|
||||
}
|
||||
|
||||
removefiles {
|
||||
path.join(protobuf.source, "src/**/*test.cc"),
|
||||
path.join(protobuf.source, "src/google/protobuf/*test*.cc"),
|
||||
|
||||
path.join(protobuf.source, "src/google/protobuf/testing/**.cc"),
|
||||
path.join(protobuf.source, "src/google/protobuf/compiler/**.cc"),
|
||||
|
||||
path.join(protobuf.source, "src/google/protobuf/arena_nc.cc"),
|
||||
path.join(protobuf.source, "src/google/protobuf/util/internal/error_listener.cc"),
|
||||
path.join(protobuf.source, "**/*_gcc.cc"),
|
||||
}
|
||||
|
||||
rules {
|
||||
"ProtobufCompiler"
|
||||
}
|
||||
|
||||
defines {
|
||||
"_SCL_SECURE_NO_WARNINGS",
|
||||
"_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS",
|
||||
"_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS",
|
||||
}
|
||||
|
||||
linkoptions {
|
||||
"-IGNORE:4221"
|
||||
}
|
||||
|
||||
warnings "Off"
|
||||
kind "StaticLib"
|
||||
end
|
||||
|
||||
table.insert(dependencies, protobuf)
|
19
deps/premake/rapidjson.lua
vendored
Normal file
19
deps/premake/rapidjson.lua
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
rapidjson = {
|
||||
source = path.join(dependencies.basePath, "rapidjson"),
|
||||
}
|
||||
|
||||
function rapidjson.import()
|
||||
rapidjson.includes()
|
||||
end
|
||||
|
||||
function rapidjson.includes()
|
||||
includedirs {
|
||||
path.join(rapidjson.source, "include"),
|
||||
}
|
||||
end
|
||||
|
||||
function rapidjson.project()
|
||||
|
||||
end
|
||||
|
||||
table.insert(dependencies, rapidjson)
|
37
deps/premake/udis86.lua
vendored
Normal file
37
deps/premake/udis86.lua
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
udis86 = {
|
||||
source = path.join(dependencies.basePath, "udis86"),
|
||||
}
|
||||
|
||||
function udis86.import()
|
||||
links {
|
||||
"udis86"
|
||||
}
|
||||
|
||||
udis86.includes()
|
||||
end
|
||||
|
||||
function udis86.includes()
|
||||
includedirs {
|
||||
udis86.source,
|
||||
path.join(udis86.source, "libudis86"),
|
||||
path.join(dependencies.basePath, "extra/udis86"),
|
||||
path.join(dependencies.basePath, "extra/udis86/libudis86"),
|
||||
}
|
||||
end
|
||||
|
||||
function udis86.project()
|
||||
project "udis86"
|
||||
language "C"
|
||||
|
||||
udis86.includes()
|
||||
|
||||
files {
|
||||
path.join(udis86.source, "libudis86/*.c"),
|
||||
path.join(dependencies.basePath, "extra/udis86/libudis86/*.c"),
|
||||
}
|
||||
|
||||
warnings "Off"
|
||||
kind "StaticLib"
|
||||
end
|
||||
|
||||
table.insert(dependencies, udis86)
|
1
deps/protobuf
vendored
Submodule
1
deps/protobuf
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit c9d2bd2fc781fe67ebf306807b9b6edb4a0d2764
|
1
deps/rapidjson
vendored
Submodule
1
deps/rapidjson
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit ce81bc9edfe773667a7a4454ba81dac72ed4364c
|
1
deps/udis86
vendored
Submodule
1
deps/udis86
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 56ff6c87c11de0ffa725b14339004820556e343d
|
37
premake5.lua
37
premake5.lua
@ -36,8 +36,8 @@ newoption {
|
||||
|
||||
dependencies.load()
|
||||
|
||||
workspace "iw4x²"
|
||||
startproject "iw4x²"
|
||||
workspace "w3x"
|
||||
startproject "w3x"
|
||||
location "./build"
|
||||
objdir "%{wks.location}/obj"
|
||||
targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
|
||||
@ -47,8 +47,8 @@ workspace "iw4x²"
|
||||
"Release",
|
||||
}
|
||||
|
||||
architecture "x32"
|
||||
platforms "x32"
|
||||
architecture "x64"
|
||||
platforms "x64"
|
||||
|
||||
buildoptions "/std:c++latest"
|
||||
systemversion "latest"
|
||||
@ -57,7 +57,7 @@ workspace "iw4x²"
|
||||
editandcontinue "Off"
|
||||
warnings "Extra"
|
||||
characterset "ASCII"
|
||||
|
||||
|
||||
flags {
|
||||
"NoIncrementalLink",
|
||||
"NoMinimalRebuild",
|
||||
@ -93,16 +93,12 @@ workspace "iw4x²"
|
||||
|
||||
configuration {}
|
||||
|
||||
project "iw4x²"
|
||||
kind "ConsoleApp"
|
||||
project "w3x"
|
||||
kind "WindowedApp"
|
||||
language "C++"
|
||||
|
||||
pchheader "std_include.hpp"
|
||||
pchsource "src/std_include.cpp"
|
||||
|
||||
linkoptions "/IGNORE:4254 /DYNAMICBASE:NO /SAFESEH:NO /LARGEADDRESSAWARE"
|
||||
linkoptions "/LAST:.main"
|
||||
|
||||
|
||||
files {
|
||||
"./src/**.rc",
|
||||
@ -112,7 +108,8 @@ workspace "iw4x²"
|
||||
}
|
||||
|
||||
includedirs {
|
||||
"./src"
|
||||
"./src",
|
||||
"%{prj.location}/src",
|
||||
}
|
||||
|
||||
resincludedirs {
|
||||
@ -129,3 +126,19 @@ workspace "iw4x²"
|
||||
|
||||
group "Dependencies"
|
||||
dependencies.projects()
|
||||
|
||||
rule "ProtobufCompiler"
|
||||
display "Protobuf compiler"
|
||||
location "./build"
|
||||
fileExtension ".proto"
|
||||
buildmessage "Compiling %(Identity) with protoc..."
|
||||
buildcommands {
|
||||
'@echo off',
|
||||
'path "$(SolutionDir)\\..\\tools"',
|
||||
'if not exist "$(ProjectDir)\\src\\proto" mkdir "$(ProjectDir)\\src\\proto"',
|
||||
'protoc --error_format=msvs -I=%(RelativeDir) --cpp_out=src\\proto %(Identity)',
|
||||
}
|
||||
buildoutputs {
|
||||
'$(ProjectDir)\\src\\proto\\%(Filename).pb.cc',
|
||||
'$(ProjectDir)\\src\\proto\\%(Filename).pb.h',
|
||||
}
|
5
src/a.cpp
Normal file
5
src/a.cpp
Normal file
@ -0,0 +1,5 @@
|
||||
#include "std_include.hpp"
|
||||
|
||||
// The naming of the file enforces early linking and thus
|
||||
// a better placement in the tls segment
|
||||
__declspec(thread) char tls_data[TLS_PAYLOAD_SIZE];
|
120
src/loader/loader.cpp
Normal file
120
src/loader/loader.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader.hpp"
|
||||
#include "utils/string.hpp"
|
||||
|
||||
namespace loader
|
||||
{
|
||||
utils::nt::module game_module;
|
||||
utils::nt::module main_module;
|
||||
|
||||
void load_imports(const utils::nt::module& target, const resolver& import_resolver)
|
||||
{
|
||||
const auto import_directory = &target.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
|
||||
auto descriptor = PIMAGE_IMPORT_DESCRIPTOR(target.get_ptr() + import_directory->VirtualAddress);
|
||||
|
||||
while (descriptor->Name)
|
||||
{
|
||||
std::string name = LPSTR(target.get_ptr() + descriptor->Name);
|
||||
|
||||
auto name_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->OriginalFirstThunk);
|
||||
auto address_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->FirstThunk);
|
||||
|
||||
if (!descriptor->OriginalFirstThunk)
|
||||
{
|
||||
name_table_entry = reinterpret_cast<uintptr_t*>(target.get_ptr() + descriptor->FirstThunk);
|
||||
}
|
||||
|
||||
while (*name_table_entry)
|
||||
{
|
||||
FARPROC function = nullptr;
|
||||
std::string function_name;
|
||||
|
||||
if (IMAGE_SNAP_BY_ORDINAL(*name_table_entry))
|
||||
{
|
||||
auto module = utils::nt::module::load(name);
|
||||
if (module)
|
||||
{
|
||||
function = GetProcAddress(module, MAKEINTRESOURCEA(IMAGE_ORDINAL(*name_table_entry)));
|
||||
}
|
||||
|
||||
function_name = "#" + std::to_string(IMAGE_ORDINAL(*name_table_entry));
|
||||
}
|
||||
else
|
||||
{
|
||||
auto import = PIMAGE_IMPORT_BY_NAME(target.get_ptr() + *name_table_entry);
|
||||
function_name = import->Name;
|
||||
|
||||
if (import_resolver)
|
||||
{
|
||||
function = FARPROC(import_resolver(name, function_name));
|
||||
}
|
||||
|
||||
if (!function)
|
||||
{
|
||||
auto module = utils::nt::module::load(name);
|
||||
if (module)
|
||||
{
|
||||
function = GetProcAddress(module, function_name.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!function)
|
||||
{
|
||||
throw std::runtime_error(utils::string::va("Unable to load import '%s' from module '%s'", function_name.data(), name.data()));
|
||||
}
|
||||
|
||||
DWORD old_protect;
|
||||
VirtualProtect(address_table_entry, sizeof(*address_table_entry), PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
*address_table_entry = reinterpret_cast<uintptr_t>(function);
|
||||
|
||||
name_table_entry++;
|
||||
address_table_entry++;
|
||||
}
|
||||
|
||||
descriptor++;
|
||||
}
|
||||
}
|
||||
|
||||
utils::nt::module get_game_module()
|
||||
{
|
||||
return game_module;
|
||||
}
|
||||
|
||||
utils::nt::module get_main_module()
|
||||
{
|
||||
return main_module;
|
||||
}
|
||||
|
||||
utils::nt::module load(const std::string& name, const resolver& import_resolver)
|
||||
{
|
||||
game_module = utils::nt::module::load(name);
|
||||
if(!game_module)
|
||||
{
|
||||
throw std::runtime_error(utils::string::va("Unable to load '%s'", name.data()));
|
||||
}
|
||||
|
||||
load_imports(game_module, import_resolver);
|
||||
|
||||
return game_module;
|
||||
}
|
||||
|
||||
size_t reverse_g(const size_t val)
|
||||
{
|
||||
static auto base = size_t(loader::get_game_module().get_ptr());
|
||||
assert(base != size_t(loader::get_main_module().get_ptr()));
|
||||
return 0x140000000 + (val - base);
|
||||
}
|
||||
|
||||
size_t reverse_g(const void* val)
|
||||
{
|
||||
return reverse_g(size_t(val));
|
||||
}
|
||||
}
|
||||
|
||||
size_t operator"" _g(const size_t val)
|
||||
{
|
||||
static auto base = size_t(loader::get_game_module().get_ptr());
|
||||
assert(base != size_t(loader::get_main_module().get_ptr()));
|
||||
return base + (val - 0x140000000);
|
||||
}
|
17
src/loader/loader.hpp
Normal file
17
src/loader/loader.hpp
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include "utils/nt.hpp"
|
||||
|
||||
namespace loader
|
||||
{
|
||||
using resolver = std::function<void*(const std::string& module, const std::string & function)>;
|
||||
|
||||
utils::nt::module get_game_module();
|
||||
utils::nt::module get_main_module();
|
||||
utils::nt::module load(const std::string& name, const resolver& import_resolver = {});
|
||||
|
||||
size_t reverse_g(size_t val);
|
||||
size_t reverse_g(const void* val);
|
||||
}
|
||||
|
||||
// Outside the namespace for easier use
|
||||
size_t operator"" _g(size_t val);
|
26
src/loader/module.hpp
Normal file
26
src/loader/module.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
class module
|
||||
{
|
||||
public:
|
||||
virtual ~module()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void post_start()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void post_load()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void pre_destroy()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void* load_import([[maybe_unused]] const std::string& module, [[maybe_unused]] const std::string& function)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
100
src/loader/module_loader.cpp
Normal file
100
src/loader/module_loader.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include <std_include.hpp>
|
||||
#include "module_loader.hpp"
|
||||
|
||||
std::vector<std::unique_ptr<module>>* module_loader::modules_ = nullptr;
|
||||
|
||||
void module_loader::register_module(std::unique_ptr<module>&& module_)
|
||||
{
|
||||
if (!modules_)
|
||||
{
|
||||
modules_ = new std::vector<std::unique_ptr<module>>();
|
||||
atexit(destroy_modules);
|
||||
}
|
||||
|
||||
modules_->push_back(std::move(module_));
|
||||
}
|
||||
|
||||
bool module_loader::post_start()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled || !modules_) return true;
|
||||
handled = true;
|
||||
|
||||
try
|
||||
{
|
||||
for (const auto& module_ : *modules_)
|
||||
{
|
||||
module_->post_start();
|
||||
}
|
||||
}
|
||||
catch (premature_shutdown_trigger&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool module_loader::post_load()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled || !modules_) return true;
|
||||
handled = true;
|
||||
|
||||
try
|
||||
{
|
||||
for (const auto& module_ : *modules_)
|
||||
{
|
||||
module_->post_load();
|
||||
}
|
||||
}
|
||||
catch (premature_shutdown_trigger&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void module_loader::pre_destroy()
|
||||
{
|
||||
static auto handled = false;
|
||||
if (handled || !modules_) return;
|
||||
handled = true;
|
||||
|
||||
for (const auto& module_ : *modules_)
|
||||
{
|
||||
module_->pre_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
void* module_loader::load_import(const std::string& module, const std::string& function)
|
||||
{
|
||||
void* function_ptr = nullptr;
|
||||
|
||||
for (const auto& module_ : *modules_)
|
||||
{
|
||||
const auto module_function_ptr = module_->load_import(module, function);
|
||||
if (module_function_ptr)
|
||||
{
|
||||
function_ptr = module_function_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return function_ptr;
|
||||
}
|
||||
|
||||
void module_loader::destroy_modules()
|
||||
{
|
||||
pre_destroy();
|
||||
|
||||
if (!modules_) return;
|
||||
|
||||
delete modules_;
|
||||
modules_ = nullptr;
|
||||
}
|
||||
|
||||
void module_loader::trigger_premature_shutdown()
|
||||
{
|
||||
throw premature_shutdown_trigger();
|
||||
}
|
61
src/loader/module_loader.hpp
Normal file
61
src/loader/module_loader.hpp
Normal file
@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
#include "module.hpp"
|
||||
|
||||
class module_loader final
|
||||
{
|
||||
public:
|
||||
class premature_shutdown_trigger final : public std::exception
|
||||
{
|
||||
[[nodiscard]] const char* what() const noexcept override
|
||||
{
|
||||
return "Premature shutdown requested";
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class installer final
|
||||
{
|
||||
static_assert(std::is_base_of<module, T>::value, "Module has invalid base class");
|
||||
|
||||
public:
|
||||
installer()
|
||||
{
|
||||
register_module(std::make_unique<T>());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
static T* get()
|
||||
{
|
||||
for (const auto& module_ : *modules_)
|
||||
{
|
||||
if (typeid(*module_.get()) == typeid(T))
|
||||
{
|
||||
return reinterpret_cast<T*>(module_.get());
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void register_module(std::unique_ptr<module>&& module);
|
||||
|
||||
static bool post_start();
|
||||
static bool post_load();
|
||||
static void pre_destroy();
|
||||
|
||||
static void* load_import(const std::string& module, const std::string& function);
|
||||
|
||||
static void trigger_premature_shutdown();
|
||||
|
||||
private:
|
||||
static std::vector<std::unique_ptr<module>>* modules_;
|
||||
|
||||
static void destroy_modules();
|
||||
};
|
||||
|
||||
#define REGISTER_MODULE(name) \
|
||||
namespace \
|
||||
{ \
|
||||
static module_loader::installer<name> $_##name; \
|
||||
}
|
78
src/main.cpp
78
src/main.cpp
@ -1,7 +1,79 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/loader.hpp"
|
||||
#include "utils/string.hpp"
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
int main()
|
||||
DECLSPEC_NORETURN void WINAPI exit_hook(const int code)
|
||||
{
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
return 0;
|
||||
module_loader::pre_destroy();
|
||||
exit(code);
|
||||
}
|
||||
|
||||
void verify_tls()
|
||||
{
|
||||
const auto self = loader::get_main_module();
|
||||
const auto self_tls = reinterpret_cast<PIMAGE_TLS_DIRECTORY>(self.get_ptr()
|
||||
+ self.get_optional_header()->DataDirectory[IMAGE_DIRECTORY_ENTRY_TLS].VirtualAddress);
|
||||
|
||||
const auto ref = DWORD64(&tls_data);
|
||||
const auto tls_index = *reinterpret_cast<PDWORD>(self_tls->AddressOfIndex);
|
||||
const auto tls_vector = *reinterpret_cast<PDWORD64>(__readgsqword(0x58) + 8ull * tls_index);
|
||||
const auto offset = ref - tls_vector;
|
||||
|
||||
if (offset != 0 && offset != 16) // Actually 16 is bad, but I think msvc places custom stuff before
|
||||
{
|
||||
throw std::runtime_error(utils::string::va("TLS payload is at offset 0x%X, but should be at 0!", offset));
|
||||
}
|
||||
}
|
||||
|
||||
int __stdcall WinMain(HINSTANCE, HINSTANCE, PSTR, int)
|
||||
{
|
||||
FARPROC entry_point;
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
|
||||
{
|
||||
auto premature_shutdown = true;
|
||||
const auto _ = gsl::finally([&premature_shutdown]()
|
||||
{
|
||||
if (premature_shutdown)
|
||||
{
|
||||
module_loader::pre_destroy();
|
||||
}
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
verify_tls();
|
||||
if (!module_loader::post_start()) return 0;
|
||||
|
||||
const auto module = loader::load("witcher3.exe", [](const std::string& module, const std::string& function) -> void*
|
||||
{
|
||||
if (function == "ExitProcess")
|
||||
{
|
||||
return &exit_hook;
|
||||
}
|
||||
|
||||
return module_loader::load_import(module, function);
|
||||
});
|
||||
|
||||
const auto version_sig = "48 FF 42 30 48 8D 05 ? ? ? ?"_sig;
|
||||
if(version_sig.count() != 1 || utils::hook::extract<char*>(version_sig.get(0) + 0x7) != "v 1.32"s)
|
||||
{
|
||||
throw std::runtime_error("Unsupported game version");
|
||||
}
|
||||
|
||||
entry_point = FARPROC(module.get_entry_point());
|
||||
|
||||
if (!module_loader::post_load()) return 0;
|
||||
premature_shutdown = false;
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
MessageBoxA(nullptr, e.what(), "ERROR", MB_ICONERROR);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return static_cast<int>(entry_point());
|
||||
}
|
||||
|
31
src/module/camera.cpp
Normal file
31
src/module/camera.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
class camera final : public module
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
const auto handle_input = "48 83 EC 38 80 3D ? ? ? ? ? 74 3D"_sig.get(0);
|
||||
handle_input_hook = utils::hook::detour(handle_input, &handle_debug_input);
|
||||
}
|
||||
|
||||
private:
|
||||
static utils::hook::detour handle_input_hook;
|
||||
|
||||
static bool handle_debug_input(void* this_ptr, void* viewport, const uint64_t input_key, const uint64_t input_action, const float tick)
|
||||
{
|
||||
static const auto handle_camera_input = "48 89 5C 24 ? 48 89 74 24 ? 57 48 83 EC 40 80 3D ? ? ? ? ?"_sig.get(0);
|
||||
if(utils::hook::invoke<bool>(handle_camera_input, this_ptr, input_key, input_action, tick))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return handle_input_hook.invoke<bool>(this_ptr, viewport, input_key, input_action, tick);
|
||||
}
|
||||
};
|
||||
|
||||
utils::hook::detour camera::handle_input_hook;
|
||||
|
||||
REGISTER_MODULE(camera)
|
26
src/module/console.cpp
Normal file
26
src/module/console.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
class console final : public module
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
// Enable ingame console
|
||||
const auto config_vars = "4C 8D 05 ? ? ? ? 48 8D 15 ? ? ? ? 48 8D 0D ? ? ? ? 45 33 C9 C7 44 24"_sig;
|
||||
|
||||
for(size_t i = 0; i < config_vars.count(); ++i)
|
||||
{
|
||||
const auto var = config_vars.get(i);
|
||||
const auto string = utils::hook::extract<char*>(var + 3);
|
||||
if(string == "DBGConsoleOn"s)
|
||||
{
|
||||
utils::hook::set<BYTE>(var + 0x6F, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_MODULE(console)
|
241
src/module/experiments.cpp
Normal file
241
src/module/experiments.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
#include "utils/string.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
#include "renderer.hpp"
|
||||
|
||||
template<typename T>
|
||||
struct rva
|
||||
{
|
||||
uint32_t value;
|
||||
|
||||
using type = T*;
|
||||
type operator->() const
|
||||
{
|
||||
const auto addr = loader::get_game_module().get_ptr() + this->value;
|
||||
return type(addr);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(rva<void>) == 4);
|
||||
|
||||
struct rtti_type_descriptor
|
||||
{
|
||||
void* typeInfo;
|
||||
size_t runtime_reference;
|
||||
char name[1];
|
||||
};
|
||||
|
||||
struct rtti_object_locator
|
||||
{
|
||||
uint32_t signature;
|
||||
uint32_t offset_in_class;
|
||||
uint32_t offset_of_constructor;
|
||||
rva<rtti_type_descriptor> type_description;
|
||||
rva<void> hierarchy_description;
|
||||
rva<void> object_base;
|
||||
};
|
||||
|
||||
rtti_object_locator* get_rtti(void* object)
|
||||
{
|
||||
auto* vtable = *static_cast<void**>(object);
|
||||
return static_cast<rtti_object_locator**>(vtable)[-1];
|
||||
}
|
||||
|
||||
struct CR4Player_Vtable
|
||||
{
|
||||
void* x;
|
||||
};
|
||||
|
||||
struct CR4Player
|
||||
{
|
||||
CR4Player_Vtable* vftbl;
|
||||
char pad1[0x68];
|
||||
float rotation[12]; // 3x4
|
||||
float position[3];
|
||||
|
||||
void get_orientation(float* orientation)
|
||||
{
|
||||
static const auto get_player_orientation = utils::hook::follow_branch("E8 ? ? ? ? 45 8B 0C 24 "_sig.get(0));
|
||||
utils::hook::invoke<void>(get_player_orientation, this->rotation, orientation);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(offsetof(CR4Player, rotation) == 0x70);
|
||||
static_assert(offsetof(CR4Player, position) == 0xA0);
|
||||
|
||||
struct CCamera // Name is probably wrong
|
||||
{
|
||||
float position[4];
|
||||
float orientation[3];
|
||||
float position_2[4];
|
||||
float orientation_2[3];
|
||||
};
|
||||
|
||||
struct CR4Game;
|
||||
struct CR4Game_Vtable
|
||||
{
|
||||
char pad[0x1F0];
|
||||
CR4Player*(*get_player)(CR4Game*);
|
||||
};
|
||||
|
||||
static_assert(offsetof(CR4Game_Vtable, get_player) == 0x1F0);
|
||||
|
||||
struct CR4Game
|
||||
{
|
||||
CR4Game_Vtable* vftbl;
|
||||
char pad2[0x116];
|
||||
char pad3;
|
||||
bool free_camera_enabled;
|
||||
char pad4[0x428];
|
||||
CCamera* camera;
|
||||
};
|
||||
|
||||
static_assert(offsetof(CR4Game, free_camera_enabled) == 0x11F);
|
||||
static_assert(offsetof(CR4Game, camera) == 0x548);
|
||||
|
||||
static CR4Game* get_global_game()
|
||||
{
|
||||
static const auto game = utils::hook::extract<CR4Game**>("E8 ? ? ? ? 48 8B 0D ? ? ? ? 48 8B 55 C0"_sig.get(0) + 8);
|
||||
return *game;
|
||||
}
|
||||
|
||||
struct IDK
|
||||
{
|
||||
void* viewport;
|
||||
};
|
||||
|
||||
struct CRendererInterface
|
||||
{
|
||||
void* vftbl;
|
||||
IDK* idk;
|
||||
};
|
||||
|
||||
struct StrInfo
|
||||
{
|
||||
void* idk;
|
||||
size_t strlen;
|
||||
void* idk2;
|
||||
size_t strlen2;
|
||||
};
|
||||
|
||||
struct SubTextRenderStruct
|
||||
{
|
||||
const wchar_t* text;
|
||||
size_t length;
|
||||
size_t length2;
|
||||
void* idk;
|
||||
StrInfo* info;
|
||||
};
|
||||
|
||||
struct SomeTextRenderStruct
|
||||
{
|
||||
char pad[0x30];
|
||||
SubTextRenderStruct* sub_struct;
|
||||
};
|
||||
|
||||
utils::hook::detour register_script_hook;
|
||||
utils::hook::detour render_text_hook;
|
||||
|
||||
void* render_text_function(SomeTextRenderStruct* r, const size_t idk)
|
||||
{
|
||||
auto old = r->sub_struct->text;
|
||||
/*auto old_len = r->sub_struct->length;
|
||||
auto old_len2 = r->sub_struct->length2;
|
||||
auto old_info = *r->sub_struct->info;*/
|
||||
|
||||
r->sub_struct->text = L"LUUUL";
|
||||
/*r->sub_struct->info->strlen = wcslen(r->sub_struct->text);
|
||||
r->sub_struct->info->strlen2 = r->sub_struct->info->strlen;
|
||||
r->sub_struct->length = r->sub_struct->info->strlen + 1;
|
||||
r->sub_struct->length2 = r->sub_struct->length;*/
|
||||
|
||||
auto _ = gsl::finally([&]()
|
||||
{
|
||||
r->sub_struct->text = old;
|
||||
/*r->sub_struct->length = old_len;
|
||||
r->sub_struct->length2 = old_len2;
|
||||
*r->sub_struct->info = old_info;*/
|
||||
});
|
||||
|
||||
return render_text_hook.invoke<void*>(r, idk);
|
||||
}
|
||||
|
||||
void register_script_function(const size_t idk, const wchar_t* function)
|
||||
{
|
||||
//OutputDebugStringW(function);
|
||||
//OutputDebugStringA("\n");
|
||||
register_script_hook.invoke<void>(idk, function);
|
||||
}
|
||||
|
||||
void execute_command([[maybe_unused]] const std::string& command)
|
||||
{
|
||||
auto* renderer = *reinterpret_cast<CRendererInterface**>(0x142BCBB48_g);
|
||||
const auto viewport = renderer->idk->viewport;
|
||||
|
||||
auto* console = *reinterpret_cast<void**>(0x142BD98C8_g);
|
||||
const auto handler = 0x140243A20_g;
|
||||
|
||||
const auto in = [&](const uint64_t chr)
|
||||
{
|
||||
utils::hook::invoke<bool>(handler, console, viewport, 1, chr, 0.0f);
|
||||
utils::hook::invoke<bool>(handler, console, viewport, 2, chr, 0.0f);
|
||||
};
|
||||
|
||||
in(192);
|
||||
|
||||
/*
|
||||
for (const auto& chr : command)
|
||||
{
|
||||
in(chr);
|
||||
}
|
||||
|
||||
in(13);
|
||||
*/
|
||||
}
|
||||
|
||||
class experiments final : public module
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
//register_script_hook = utils::hook::detour(utils::hook::signature("E8 ? ? ? ? 8B 4D 94").process().get(0), ®ister_script_function);
|
||||
//render_text_hook = utils::hook::detour(0x141394F90_g, &render_text_function);
|
||||
|
||||
renderer::frame([]()
|
||||
{
|
||||
static auto last_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
const auto game = get_global_game();
|
||||
if (game && game->vftbl)
|
||||
{
|
||||
/*
|
||||
const auto game_rtti = get_rtti(game);
|
||||
const auto type_desc = game_rtti->type_description;
|
||||
OutputDebugStringA(type_desc->name);
|
||||
*/
|
||||
|
||||
const auto player = game->vftbl->get_player(game);
|
||||
if (player)
|
||||
{
|
||||
float orientation[3];
|
||||
player->get_orientation(orientation);
|
||||
|
||||
const auto duration = std::chrono::high_resolution_clock::now() - last_time;
|
||||
const auto fps = static_cast<int>(1000.0 / std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
|
||||
last_time = std::chrono::high_resolution_clock::now();
|
||||
|
||||
std::string text;
|
||||
text += utils::string::va("Position: %.2f %.2f %.2f\n", player->position[0], player->position[1], player->position[2]);
|
||||
text += utils::string::va("Orientation: %.2f %.2f %.2f\n", orientation[0], orientation[1], orientation[2]);
|
||||
text += utils::string::va("FPS: %d", fps);
|
||||
|
||||
renderer::draw_text(text, { 10.0f, 30.0f }, "#7BFF00");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_MODULE(experiments)
|
103
src/module/filesystem.cpp
Normal file
103
src/module/filesystem.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
class filesystem final : public module
|
||||
{
|
||||
public:
|
||||
void post_load() override
|
||||
{
|
||||
const auto module = loader::get_main_module();
|
||||
const auto path = module.get_folder() + "/";
|
||||
const std::wstring wide_path(path.begin(), path.end());
|
||||
|
||||
static struct game_string
|
||||
{
|
||||
const wchar_t* string;
|
||||
size_t length;
|
||||
wchar_t path[MAX_PATH];
|
||||
} game_path;
|
||||
|
||||
game_path.string = game_path.path;
|
||||
game_path.length = wide_path.size() + 1;
|
||||
wcscpy_s(game_path.path, wide_path.data());
|
||||
|
||||
[[maybe_unused]] const auto mods_path_stub = utils::hook::assemble([](utils::hook::assembler& a)
|
||||
{
|
||||
a.mov(rcx, size_t(&game_path));
|
||||
|
||||
a.lea(rdx, ptr(rbp, -0x48, 8));
|
||||
a.mov(ptr(rsp, 0x2d8, 8), rbx);
|
||||
a.jmp(0x140049B74_g);
|
||||
});
|
||||
|
||||
//utils::hook::jump(0x140049B68_g, mods_path_stub);
|
||||
|
||||
[[maybe_unused]] const auto mods_path_stub_2 = utils::hook::assemble([](utils::hook::assembler& a)
|
||||
{
|
||||
a.mov(rcx, size_t(&game_path));
|
||||
a.lea(r8, ptr(rsp, 0x40, 8));
|
||||
a.jmp(0x140049BDD_g);
|
||||
});
|
||||
|
||||
//utils::hook::jump(0x140049BD1_g, mods_path_stub_2);
|
||||
}
|
||||
|
||||
void* load_import(const std::string& /*module*/, const std::string& function) override
|
||||
{
|
||||
if (function == "CreateFileA")
|
||||
{
|
||||
return &create_file_a;
|
||||
}
|
||||
|
||||
if (function == "CreateFileW")
|
||||
{
|
||||
return &create_file_w;
|
||||
}
|
||||
|
||||
if (function == "FindFirstFileExW")
|
||||
{
|
||||
return &find_first_file_ex_w;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
static HANDLE __stdcall find_first_file_ex_w(const wchar_t* file_name, FINDEX_INFO_LEVELS info_level_id,
|
||||
LPVOID find_file_data, FINDEX_SEARCH_OPS search_op,
|
||||
LPVOID search_filter, DWORD additional_flags)
|
||||
{
|
||||
OutputDebugStringW(file_name);
|
||||
if (file_name == L"D:\\Games\\SteamLibrary\\steamapps\\common\\The Witcher 3\\mods\\*."s)
|
||||
{
|
||||
OutputDebugStringA("");
|
||||
}
|
||||
|
||||
return FindFirstFileExW(file_name, info_level_id, find_file_data, search_op, search_filter, additional_flags);
|
||||
}
|
||||
|
||||
static HANDLE __stdcall create_file_a(const char* filename, const DWORD desired_access, const DWORD share_mode,
|
||||
const LPSECURITY_ATTRIBUTES security_attributes,
|
||||
const DWORD creation_disposition, const DWORD flags_and_attributes,
|
||||
const HANDLE template_file)
|
||||
{
|
||||
//OutputDebugStringA(filename);
|
||||
|
||||
return CreateFileA(filename, desired_access, share_mode, security_attributes, creation_disposition,
|
||||
flags_and_attributes, template_file);
|
||||
}
|
||||
|
||||
static HANDLE __stdcall create_file_w(const wchar_t* filename, const DWORD desired_access, const DWORD share_mode,
|
||||
const LPSECURITY_ATTRIBUTES security_attributes,
|
||||
const DWORD creation_disposition, const DWORD flags_and_attributes,
|
||||
const HANDLE template_file)
|
||||
{
|
||||
return CreateFileW(filename, desired_access, share_mode, security_attributes,
|
||||
creation_disposition,
|
||||
flags_and_attributes, template_file);
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_MODULE(filesystem)
|
97
src/module/game_module.cpp
Normal file
97
src/module/game_module.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/loader.hpp"
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
class game_module final : public module
|
||||
{
|
||||
public:
|
||||
void post_start() override
|
||||
{
|
||||
handle_a_hook_ = utils::hook::detour(&GetModuleHandleA, &get_module_handle_a);
|
||||
handle_w_hook_ = utils::hook::detour(&GetModuleHandleW, &get_module_handle_w);
|
||||
handle_ex_w_hook_ = utils::hook::detour(&GetModuleHandleExA, &get_module_handle_ex_a);
|
||||
handle_ex_w_hook_ = utils::hook::detour(&GetModuleHandleExW, &get_module_handle_ex_w);
|
||||
file_name_a_hook_ = utils::hook::detour(&GetModuleFileNameA, &get_module_file_name_a);
|
||||
file_name_w_hook_ = utils::hook::detour(&GetModuleFileNameW, &get_module_file_name_w);
|
||||
}
|
||||
|
||||
private:
|
||||
static utils::hook::detour handle_a_hook_;
|
||||
static utils::hook::detour handle_w_hook_;
|
||||
static utils::hook::detour handle_ex_a_hook_;
|
||||
static utils::hook::detour handle_ex_w_hook_;
|
||||
static utils::hook::detour file_name_a_hook_;
|
||||
static utils::hook::detour file_name_w_hook_;
|
||||
|
||||
static HMODULE __stdcall get_module_handle_a(const LPCSTR module_name)
|
||||
{
|
||||
if (!module_name)
|
||||
{
|
||||
return loader::get_game_module();
|
||||
}
|
||||
|
||||
return handle_a_hook_.invoke<HMODULE>(module_name);
|
||||
}
|
||||
|
||||
static HMODULE __stdcall get_module_handle_w(const LPWSTR module_name)
|
||||
{
|
||||
if (!module_name)
|
||||
{
|
||||
return loader::get_game_module();
|
||||
}
|
||||
|
||||
return handle_w_hook_.invoke<HMODULE>(module_name);
|
||||
}
|
||||
|
||||
static BOOL __stdcall get_module_handle_ex_a(const DWORD flags, const LPCSTR module_name, HMODULE* module)
|
||||
{
|
||||
if (!module_name)
|
||||
{
|
||||
*module = loader::get_game_module();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return handle_ex_a_hook_.invoke<BOOL>(flags, module_name, module);
|
||||
}
|
||||
|
||||
static BOOL __stdcall get_module_handle_ex_w(const DWORD flags, const LPCWSTR module_name, HMODULE* module)
|
||||
{
|
||||
if (!module_name)
|
||||
{
|
||||
*module = loader::get_game_module();
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return handle_ex_w_hook_.invoke<BOOL>(flags, module_name, module);
|
||||
}
|
||||
|
||||
static DWORD __stdcall get_module_file_name_a(HMODULE module, const LPSTR filename, const DWORD size)
|
||||
{
|
||||
if (!module)
|
||||
{
|
||||
module = loader::get_game_module();
|
||||
}
|
||||
|
||||
return file_name_a_hook_.invoke<DWORD>(module, filename, size);
|
||||
}
|
||||
|
||||
static DWORD __stdcall get_module_file_name_w(HMODULE module, const LPWSTR filename, const DWORD size)
|
||||
{
|
||||
if (!module)
|
||||
{
|
||||
module = loader::get_game_module();
|
||||
}
|
||||
|
||||
return file_name_w_hook_.invoke<DWORD>(module, filename, size);
|
||||
}
|
||||
};
|
||||
|
||||
utils::hook::detour game_module::handle_a_hook_;
|
||||
utils::hook::detour game_module::handle_w_hook_;
|
||||
utils::hook::detour game_module::handle_ex_a_hook_;
|
||||
utils::hook::detour game_module::handle_ex_w_hook_;
|
||||
utils::hook::detour game_module::file_name_a_hook_;
|
||||
utils::hook::detour game_module::file_name_w_hook_;
|
||||
|
||||
REGISTER_MODULE(game_module)
|
78
src/module/game_path.cpp
Normal file
78
src/module/game_path.cpp
Normal file
@ -0,0 +1,78 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/io.hpp"
|
||||
#include "utils/com.hpp"
|
||||
#include "properties.hpp"
|
||||
#include "steam_proxy.hpp"
|
||||
|
||||
class game_path final : public module
|
||||
{
|
||||
public:
|
||||
void post_start() override
|
||||
{
|
||||
if(!utils::io::file_exists("witcher3.exe"))
|
||||
{
|
||||
set_witcher_path();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static void set_witcher_path()
|
||||
{
|
||||
std::string path;
|
||||
if(properties::get("game_path", path) && try_set_witcher_path(path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(!utils::com::select_folder(path, "Select Witcher 3 installation path", get_default_witcher_path()))
|
||||
{
|
||||
module_loader::trigger_premature_shutdown();
|
||||
}
|
||||
else if(!try_set_witcher_path(path))
|
||||
{
|
||||
throw std::runtime_error("Witcher 3 was not found at the specified path!");
|
||||
}
|
||||
|
||||
properties::set("game_path", path);
|
||||
}
|
||||
|
||||
static bool try_set_witcher_path(const std::filesystem::path& path)
|
||||
{
|
||||
if (path.empty()) return false;
|
||||
|
||||
if(std::filesystem::exists(path / "witcher3.exe"))
|
||||
{
|
||||
set_directory(path.generic_string());
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto alt_path = std::filesystem::path(path) / "bin\\x64";
|
||||
if (std::filesystem::exists(alt_path / "witcher3.exe"))
|
||||
{
|
||||
set_directory(alt_path.generic_string());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void set_directory(const std::string& path)
|
||||
{
|
||||
SetDllDirectoryA(path.data());
|
||||
SetCurrentDirectoryA(path.data());
|
||||
}
|
||||
|
||||
static std::string get_default_witcher_path()
|
||||
{
|
||||
const auto steam_path = steam_proxy::get_steam_install_directory();
|
||||
if (steam_path.empty()) return {};
|
||||
|
||||
const auto witcher_path = steam_path / "steamapps/common/The Witcher 3";
|
||||
if (!std::filesystem::exists(witcher_path)) return {};
|
||||
|
||||
return witcher_path.generic_string();
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_MODULE(game_path)
|
76
src/module/game_save.cpp
Normal file
76
src/module/game_save.cpp
Normal file
@ -0,0 +1,76 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/loader.hpp"
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/io.hpp"
|
||||
#include "utils/nt.hpp"
|
||||
#include "utils/hook.hpp"
|
||||
|
||||
class game_save final : public module
|
||||
{
|
||||
public:
|
||||
void post_start() override
|
||||
{
|
||||
copy_settings();
|
||||
}
|
||||
|
||||
void post_load() override
|
||||
{
|
||||
const auto get_save_folder_call = "E8 ? ? ? ? 83 78 08 01 76 03 48 8B 18 4C 8D 44 24 ?"_sig.get(0);
|
||||
utils::hook::jump(utils::hook::follow_branch(get_save_folder_call), &get_save_folder);
|
||||
}
|
||||
|
||||
void* load_import([[maybe_unused]] const std::string& module, const std::string& function) override
|
||||
{
|
||||
if(function == "SHGetFolderPathW")
|
||||
{
|
||||
return &sh_get_folder_path_w;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
static void copy_settings()
|
||||
{
|
||||
const auto new_path = loader::get_main_module().get_folder() / std::filesystem::path("user");
|
||||
|
||||
CHAR documents[MAX_PATH];
|
||||
SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, documents);
|
||||
|
||||
const auto save_path = std::filesystem::path(documents) / "The Witcher 3";
|
||||
|
||||
if (std::filesystem::exists(new_path)
|
||||
|| !std::filesystem::exists(save_path)
|
||||
|| MessageBoxA(nullptr, "Do you want to import your settings and savegames from Witcher 3?",
|
||||
"Import from Witcher 3", MB_ICONINFORMATION | MB_YESNO) != IDYES) return;
|
||||
|
||||
utils::io::copy_folder(save_path, new_path);
|
||||
}
|
||||
|
||||
static void* get_save_folder()
|
||||
{
|
||||
static struct
|
||||
{
|
||||
const wchar_t* folder = L"user";
|
||||
const size_t maybe_size = wcslen(folder);
|
||||
} save_folder;
|
||||
|
||||
return &save_folder;
|
||||
}
|
||||
|
||||
static HRESULT __stdcall sh_get_folder_path_w(const HWND hwnd, const int csidl, const HANDLE token, const DWORD flags, const LPWSTR path)
|
||||
{
|
||||
if(csidl == CSIDL_MYDOCUMENTS)
|
||||
{
|
||||
const auto main = loader::get_main_module();
|
||||
const auto main_path = main.get_folder();
|
||||
const std::wstring wide_path(main_path.begin(), main_path.end());
|
||||
wcscpy_s(path, MAX_PATH, wide_path.data());
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return SHGetFolderPathW(hwnd, csidl, token, flags, path);
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_MODULE(game_save)
|
30
src/module/icon.cpp
Normal file
30
src/module/icon.cpp
Normal file
@ -0,0 +1,30 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
|
||||
class icon final : public module
|
||||
{
|
||||
public:
|
||||
void* load_import([[maybe_unused]] const std::string& module, const std::string& function) override
|
||||
{
|
||||
if (function == "LoadIconW")
|
||||
{
|
||||
return &load_icon_w;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
static HICON __stdcall load_icon_w(const HINSTANCE instance, const wchar_t* name)
|
||||
{
|
||||
if (size_t(name) <= 300 && instance == loader::get_game_module())
|
||||
{
|
||||
return LoadIconA(loader::get_main_module(), MAKEINTRESOURCE(102));
|
||||
}
|
||||
|
||||
return LoadIconW(instance, name);
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_MODULE(icon)
|
158
src/module/properties.cpp
Normal file
158
src/module/properties.cpp
Normal file
@ -0,0 +1,158 @@
|
||||
#include <std_include.hpp>
|
||||
#include "properties.hpp"
|
||||
#include "utils/nt.hpp"
|
||||
#include "utils/io.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
|
||||
properties::properties()
|
||||
{
|
||||
this->load();
|
||||
}
|
||||
|
||||
void properties::remove(const std::string& name)
|
||||
{
|
||||
auto* instance = module_loader::get<properties>();
|
||||
if (instance)
|
||||
{
|
||||
instance->remove_internal(name);
|
||||
}
|
||||
}
|
||||
|
||||
void properties::load()
|
||||
{
|
||||
std::string data;
|
||||
const auto path = get_path();
|
||||
if(utils::io::read_file(path, &data))
|
||||
{
|
||||
this->document_.Parse(data.data(), data.size());
|
||||
}
|
||||
|
||||
if(!this->document_.IsObject())
|
||||
{
|
||||
this->document_.SetObject();
|
||||
}
|
||||
}
|
||||
|
||||
void properties::save() const
|
||||
{
|
||||
rapidjson::StringBuffer buffer;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
|
||||
this->document_.Accept(writer);
|
||||
|
||||
const std::string result(buffer.GetString(), buffer.GetLength());
|
||||
utils::io::write_file(get_path(), result);
|
||||
}
|
||||
|
||||
void properties::create_member(const std::string& name)
|
||||
{
|
||||
if(!this->document_.HasMember(name.data()))
|
||||
{
|
||||
rapidjson::Value key(name.data(), rapidjson::SizeType(name.size()));
|
||||
rapidjson::Value value(rapidjson::kNullType);
|
||||
this->document_.AddMember(key, value, this->document_.GetAllocator());
|
||||
}
|
||||
}
|
||||
|
||||
std::string properties::get_path()
|
||||
{
|
||||
const auto out_folder = std::filesystem::path(loader::get_main_module().get_folder());
|
||||
const auto out_path = out_folder / "w3x.json";
|
||||
return out_path.generic_string();
|
||||
}
|
||||
|
||||
void properties::remove_internal(const std::string& name)
|
||||
{
|
||||
if(this->document_.HasMember(name.data()))
|
||||
{
|
||||
this->document_.RemoveMember(name.data());
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
bool properties::get_internal(const std::string& name, std::string& value)
|
||||
{
|
||||
if(!this->document_.HasMember(name.data()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& val = this->document_[name.data()];
|
||||
if(!val.IsString())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = std::string(val.GetString(), val.GetStringLength());
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool properties::get_internal(const std::string& name, int64_t& value)
|
||||
{
|
||||
if (!this->document_.HasMember(name.data()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& val = this->document_[name.data()];
|
||||
if (!val.IsInt64())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = val.GetInt64();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool properties::get_internal(const std::string& name, double& value)
|
||||
{
|
||||
if (!this->document_.HasMember(name.data()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& val = this->document_[name.data()];
|
||||
if (!val.IsDouble())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = val.GetDouble();
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
void properties::set_internal(const std::string& name, const std::string& value)
|
||||
{
|
||||
this->create_member(name);
|
||||
|
||||
auto& val = this->document_[name.data()];
|
||||
val.SetString(value.data(), rapidjson::SizeType(value.size()));
|
||||
|
||||
this->save();
|
||||
}
|
||||
|
||||
template <>
|
||||
void properties::set_internal(const std::string& name, const int64_t& value)
|
||||
{
|
||||
this->create_member(name);
|
||||
|
||||
auto& val = this->document_[name.data()];
|
||||
val.SetInt64(value);
|
||||
|
||||
this->save();
|
||||
}
|
||||
|
||||
template <>
|
||||
void properties::set_internal(const std::string& name, const double& value)
|
||||
{
|
||||
this->create_member(name);
|
||||
|
||||
auto& val = this->document_[name.data()];
|
||||
val.SetDouble(value);
|
||||
|
||||
this->save();
|
||||
}
|
||||
|
||||
REGISTER_MODULE(properties);
|
49
src/module/properties.hpp
Normal file
49
src/module/properties.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
|
||||
class properties final : public module
|
||||
{
|
||||
public:
|
||||
properties();
|
||||
|
||||
template <typename T>
|
||||
static bool get(const std::string& name, T& value)
|
||||
{
|
||||
auto* instance = module_loader::get<properties>();
|
||||
if(instance)
|
||||
{
|
||||
return instance->get_internal(name, value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void set(const std::string& name, const T& value)
|
||||
{
|
||||
auto* instance = module_loader::get<properties>();
|
||||
if (instance)
|
||||
{
|
||||
instance->set_internal(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
static void remove(const std::string& name);
|
||||
|
||||
private:
|
||||
rapidjson::Document document_;
|
||||
|
||||
void load();
|
||||
void save() const;
|
||||
void create_member(const std::string& name);
|
||||
|
||||
static std::string get_path();
|
||||
|
||||
template <typename T>
|
||||
bool get_internal(const std::string& name, T& value);
|
||||
|
||||
template <typename T>
|
||||
void set_internal(const std::string& name, const T& value);
|
||||
|
||||
void remove_internal(const std::string& name);
|
||||
};
|
121
src/module/renderer.cpp
Normal file
121
src/module/renderer.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include <std_include.hpp>
|
||||
#include "utils/hook.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
#include "renderer.hpp"
|
||||
|
||||
renderer::color::color(const std::string& hex)
|
||||
{
|
||||
static const std::regex color_pattern("^#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$");
|
||||
|
||||
if(!std::regex_match(hex, color_pattern))
|
||||
{
|
||||
throw std::runtime_error("Invalid color");
|
||||
}
|
||||
|
||||
const auto parse_byte = [&](const size_t index)
|
||||
{
|
||||
char byte_text[3] = { hex[index], hex[index + 1], 0 };
|
||||
return uint8_t(strtoul(byte_text, nullptr, 16));
|
||||
};
|
||||
|
||||
this->r = parse_byte(1);
|
||||
this->g = parse_byte(3);
|
||||
this->b = parse_byte(5);
|
||||
|
||||
if(hex.size() == 9)
|
||||
{
|
||||
this->a = parse_byte(7);
|
||||
}
|
||||
}
|
||||
|
||||
renderer::color::color(const uint8_t red, const uint8_t green, const uint8_t blue, const uint8_t alpha)
|
||||
: r(red), g(green), b(blue), a(alpha)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void renderer::draw_text(const std::string& text, const position position, const color color)
|
||||
{
|
||||
auto* instance = module_loader::get<renderer>();
|
||||
if (instance)
|
||||
{
|
||||
text_command command;
|
||||
command.text.append(text.begin(), text.end());
|
||||
command.position = position;
|
||||
command.color = color;
|
||||
|
||||
std::lock_guard _(instance->mutex_);
|
||||
instance->command_queue_.push_back(command);
|
||||
}
|
||||
}
|
||||
|
||||
void renderer::frame(const std::function<void()>& callback)
|
||||
{
|
||||
auto* instance = module_loader::get<renderer>();
|
||||
if (instance)
|
||||
{
|
||||
instance->callbacks_.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void renderer::post_load()
|
||||
{
|
||||
const auto console_draw_code = "33 D2 8B 88 ? ? ? ?"_sig.get(0) + 0x3A;
|
||||
const auto render_stub = utils::hook::assemble([console_draw_code](utils::hook::assembler& a)
|
||||
{
|
||||
const auto skip_console = a.newLabel();
|
||||
|
||||
a.mov(rax, rdi);
|
||||
a.mov(rdx, rax);
|
||||
a.test(rcx, rcx);
|
||||
a.jz(skip_console);
|
||||
|
||||
a.pushad64();
|
||||
a.call(utils::hook::follow_branch(console_draw_code + 0x8));
|
||||
a.popad64();
|
||||
|
||||
a.call(&execute_frame_static);
|
||||
|
||||
a.bind(skip_console);
|
||||
a.jmp(console_draw_code + 0xD);
|
||||
});
|
||||
|
||||
utils::hook::jump(console_draw_code, render_stub);
|
||||
}
|
||||
|
||||
void renderer::execute_frame(void* a1, void* a2)
|
||||
{
|
||||
for (auto callback : this->callbacks_)
|
||||
{
|
||||
(*callback)();
|
||||
}
|
||||
|
||||
std::lock_guard _(this->mutex_);
|
||||
for (const auto& command : this->command_queue_)
|
||||
{
|
||||
draw_text_internal(a1, a2, command);
|
||||
}
|
||||
|
||||
this->command_queue_.clear();
|
||||
}
|
||||
|
||||
void renderer::execute_frame_static(void* a1, void* a2)
|
||||
{
|
||||
auto* instance = module_loader::get<renderer>();
|
||||
if (instance)
|
||||
{
|
||||
instance->execute_frame(a1, a2);
|
||||
}
|
||||
}
|
||||
|
||||
void renderer::draw_text_internal(void* a1, void* a2, const text_command& command)
|
||||
{
|
||||
text_object text{};
|
||||
text.text = command.text.data();
|
||||
text.length = uint32_t(command.text.size());
|
||||
|
||||
static const auto draw_text_func = utils::hook::follow_branch("E8 ? ? ? ? 44 39 77 38"_sig.get(0));
|
||||
utils::hook::invoke<void>(draw_text_func, a1, a2, command.position.x, command.position.y, &text, command.color);
|
||||
}
|
||||
|
||||
REGISTER_MODULE(renderer);
|
58
src/module/renderer.hpp
Normal file
58
src/module/renderer.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/concurrent_list.hpp"
|
||||
|
||||
class renderer final : public module
|
||||
{
|
||||
public:
|
||||
class position
|
||||
{
|
||||
public:
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
};
|
||||
|
||||
class color
|
||||
{
|
||||
public:
|
||||
color() = default;
|
||||
color(const std::string& hex);
|
||||
color(const char* hex) : color(std::string(hex)) {}
|
||||
color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha);
|
||||
|
||||
uint8_t r = 0xFF;
|
||||
uint8_t g = 0xFF;
|
||||
uint8_t b = 0xFF;
|
||||
uint8_t a = 0xFF;
|
||||
};
|
||||
|
||||
static void draw_text(const std::string& text, position position, color color);
|
||||
static void frame(const std::function<void()>& callback);
|
||||
|
||||
void post_load() override;
|
||||
|
||||
private:
|
||||
class text_command
|
||||
{
|
||||
public:
|
||||
std::wstring text;
|
||||
position position;
|
||||
color color;
|
||||
};
|
||||
|
||||
// TODO: Probably wrong
|
||||
struct text_object
|
||||
{
|
||||
const wchar_t* text = nullptr;
|
||||
uint32_t length = 0;
|
||||
uint32_t idk = 0;
|
||||
};
|
||||
|
||||
std::mutex mutex_;
|
||||
std::vector<text_command> command_queue_;
|
||||
utils::concurrent_list<std::function<void()>> callbacks_;
|
||||
|
||||
void execute_frame(void* a1, void* a2);
|
||||
static void execute_frame_static(void* a1, void* a2);
|
||||
static void draw_text_internal(void* a1, void* a2, const text_command& command);
|
||||
};
|
46
src/module/scheduler.cpp
Normal file
46
src/module/scheduler.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
#include <std_include.hpp>
|
||||
#include "scheduler.hpp"
|
||||
|
||||
void scheduler::frame(const std::function<bool()>& callback)
|
||||
{
|
||||
auto* instance = module_loader::get<scheduler>();
|
||||
if (instance)
|
||||
{
|
||||
instance->callbacks_.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void scheduler::execute()
|
||||
{
|
||||
for (auto callback : this->callbacks_)
|
||||
{
|
||||
const auto res = (*callback)();
|
||||
if(res == cond_end)
|
||||
{
|
||||
this->callbacks_.remove(callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void scheduler::post_start()
|
||||
{
|
||||
this->thread_ = std::thread([this]()
|
||||
{
|
||||
while(!this->kill_)
|
||||
{
|
||||
this->execute();
|
||||
std::this_thread::sleep_for(10ms);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void scheduler::pre_destroy()
|
||||
{
|
||||
this->kill_ = true;
|
||||
if(this->thread_.joinable())
|
||||
{
|
||||
this->thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_MODULE(scheduler);
|
23
src/module/scheduler.hpp
Normal file
23
src/module/scheduler.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/concurrent_list.hpp"
|
||||
|
||||
class scheduler final : public module
|
||||
{
|
||||
public:
|
||||
static const bool cond_continue = false;
|
||||
static const bool cond_end = true;
|
||||
|
||||
static void frame(const std::function<bool()>& callback);
|
||||
|
||||
void post_start() override;
|
||||
void pre_destroy() override;
|
||||
|
||||
private:
|
||||
bool kill_ = false;
|
||||
std::thread thread_;
|
||||
|
||||
utils::concurrent_list<std::function<bool()>> callbacks_;
|
||||
|
||||
void execute();
|
||||
};
|
117
src/module/splash.cpp
Normal file
117
src/module/splash.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include <std_include.hpp>
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "utils/nt.hpp"
|
||||
#include "window.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
|
||||
class splash final : public module
|
||||
{
|
||||
public:
|
||||
void post_start() override
|
||||
{
|
||||
this->show();
|
||||
|
||||
scheduler::frame([this]()
|
||||
{
|
||||
if(window::get_game_window())
|
||||
{
|
||||
this->destroy();
|
||||
return scheduler::cond_end;
|
||||
}
|
||||
|
||||
return scheduler::cond_continue;
|
||||
});
|
||||
}
|
||||
|
||||
void pre_destroy() override
|
||||
{
|
||||
this->destroy();
|
||||
|
||||
MSG msg;
|
||||
while (this->window_ && IsWindow(this->window_))
|
||||
{
|
||||
if (PeekMessageA(&msg, nullptr, NULL, NULL, PM_REMOVE))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::sleep_for(1ms);
|
||||
}
|
||||
}
|
||||
|
||||
this->window_ = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
HWND window_{};
|
||||
|
||||
void destroy() const
|
||||
{
|
||||
if (this->window_ && IsWindow(this->window_))
|
||||
{
|
||||
ShowWindow(this->window_, SW_HIDE);
|
||||
DestroyWindow(this->window_);
|
||||
UnregisterClassA("Witcher Splash Screen", loader::get_main_module());
|
||||
}
|
||||
}
|
||||
|
||||
void show()
|
||||
{
|
||||
WNDCLASSA wnd_class;
|
||||
|
||||
const auto main = loader::get_main_module();
|
||||
|
||||
wnd_class.style = 0;
|
||||
wnd_class.cbClsExtra = 0;
|
||||
wnd_class.cbWndExtra = 0;
|
||||
wnd_class.lpszMenuName = nullptr;
|
||||
wnd_class.lpfnWndProc = DefWindowProcA;
|
||||
wnd_class.hInstance = main;
|
||||
wnd_class.hIcon = LoadIconA(main, LPCSTR(102));
|
||||
wnd_class.hCursor = LoadCursorA(nullptr, IDC_APPSTARTING);
|
||||
wnd_class.hbrBackground = HBRUSH(6);
|
||||
wnd_class.lpszClassName = "Witcher Splash Screen";
|
||||
|
||||
if (RegisterClassA(&wnd_class))
|
||||
{
|
||||
const auto x_pixels = GetSystemMetrics(SM_CXFULLSCREEN);
|
||||
const auto y_pixels = GetSystemMetrics(SM_CYFULLSCREEN);
|
||||
|
||||
auto image = HWND(LoadImageA(main, MAKEINTRESOURCE(IMAGE_SPLASH), IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR));
|
||||
if (image)
|
||||
{
|
||||
this->window_ = CreateWindowExA(WS_EX_APPWINDOW, "Witcher Splash Screen", "Witcher 3: Online", WS_POPUP | WS_SYSMENU, (x_pixels - 320) / 2, (y_pixels - 100) / 2, 320, 100, nullptr, nullptr, main, nullptr);
|
||||
|
||||
if (this->window_)
|
||||
{
|
||||
const auto image_window = CreateWindowExA(0, "Static", nullptr, WS_CHILD | WS_VISIBLE | 0xEu, 0, 0, 320, 100, this->window_, nullptr, main, nullptr);
|
||||
if (image_window)
|
||||
{
|
||||
RECT rect;
|
||||
SendMessageA(image_window, 0x172u, 0, LPARAM(image));
|
||||
GetWindowRect(image_window, &rect);
|
||||
|
||||
const int width = rect.right - rect.left;
|
||||
rect.left = (x_pixels - width) / 2;
|
||||
|
||||
const int height = rect.bottom - rect.top;
|
||||
rect.top = (y_pixels - height) / 2;
|
||||
|
||||
rect.right = rect.left + width;
|
||||
rect.bottom = rect.top + height;
|
||||
AdjustWindowRect(&rect, WS_CHILD | WS_VISIBLE | 0xEu, 0);
|
||||
SetWindowPos(this->window_, nullptr, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER);
|
||||
|
||||
ShowWindow(this->window_, SW_SHOW);
|
||||
UpdateWindow(this->window_);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_MODULE(splash)
|
172
src/module/steam_proxy.cpp
Normal file
172
src/module/steam_proxy.cpp
Normal file
@ -0,0 +1,172 @@
|
||||
#include <std_include.hpp>
|
||||
#include "steam_proxy.hpp"
|
||||
#include "scheduler.hpp"
|
||||
#include "utils/string.hpp"
|
||||
#include "loader/loader.hpp"
|
||||
|
||||
steam_proxy::steam_proxy()
|
||||
{
|
||||
this->run_mod();
|
||||
}
|
||||
|
||||
void steam_proxy::post_load()
|
||||
{
|
||||
this->load_client();
|
||||
this->clean_up_on_error();
|
||||
|
||||
try
|
||||
{
|
||||
this->start_mod("Witcher 3: Online", 292030);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
printf("Steam: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void steam_proxy::pre_destroy()
|
||||
{
|
||||
if (this->steam_client_module_)
|
||||
{
|
||||
if (this->steam_pipe_)
|
||||
{
|
||||
if (this->global_user_)
|
||||
{
|
||||
this->steam_client_module_.invoke<void>("Steam_ReleaseUser", this->steam_pipe_, this->global_user_);
|
||||
}
|
||||
|
||||
this->steam_client_module_.invoke<bool>("Steam_BReleaseSteamPipe", this->steam_pipe_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void steam_proxy::run_mod() const
|
||||
{
|
||||
const auto command = "-proc ";
|
||||
const char* parent_proc = strstr(GetCommandLineA(), command);
|
||||
|
||||
if (parent_proc)
|
||||
{
|
||||
const auto pid = atoi(parent_proc + strlen(command));
|
||||
const auto process_handle = OpenProcess(SYNCHRONIZE, FALSE, pid);
|
||||
if (process_handle && process_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
WaitForSingleObject(process_handle, INFINITE);
|
||||
CloseHandle(process_handle);
|
||||
}
|
||||
|
||||
TerminateProcess(GetCurrentProcess(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void* steam_proxy::load_client_engine() const
|
||||
{
|
||||
if (!this->steam_client_module_) return nullptr;
|
||||
|
||||
for (auto i = 1; i > 0; ++i)
|
||||
{
|
||||
std::string name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i);
|
||||
const auto client_engine = this->steam_client_module_
|
||||
.invoke<void*>("CreateInterface", name.data(), nullptr);
|
||||
if (client_engine) return client_engine;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void steam_proxy::load_client()
|
||||
{
|
||||
const auto steam_path = get_steam_install_directory();
|
||||
if (steam_path.empty()) return;
|
||||
|
||||
utils::nt::module::load(steam_path / "tier0_s64.dll");
|
||||
utils::nt::module::load(steam_path / "vstdlib_s64.dll");
|
||||
this->steam_overlay_module_ = utils::nt::module::load(steam_path / "gameoverlayrenderer64.dll");
|
||||
this->steam_client_module_ = utils::nt::module::load(steam_path / "steamclient64.dll");
|
||||
if (!this->steam_client_module_) return;
|
||||
|
||||
this->client_engine_ = load_client_engine();
|
||||
if (!this->client_engine_) return;
|
||||
|
||||
this->steam_pipe_ = this->steam_client_module_.invoke<void*>("Steam_CreateSteamPipe");
|
||||
this->global_user_ = this->steam_client_module_.invoke<void*>("Steam_ConnectToGlobalUser", this->steam_pipe_);
|
||||
this->client_user_ = this->client_engine_.invoke<void*>(8, this->steam_pipe_, this->global_user_); // GetIClientUser
|
||||
this->client_utils_ = this->client_engine_.invoke<void*>(13, this->steam_pipe_); // GetIClientUtils
|
||||
}
|
||||
|
||||
void steam_proxy::start_mod(const std::string& title, size_t app_id)
|
||||
{
|
||||
if (!this->client_utils_ || !this->client_user_) return;
|
||||
|
||||
if (!this->client_user_.invoke<bool>("BIsSubscribedApp", app_id))
|
||||
{
|
||||
app_id = 480; // Spacewar
|
||||
}
|
||||
|
||||
this->client_utils_.invoke<void>("SetAppIDForCurrentPipe", app_id, false);
|
||||
|
||||
const auto self = loader::get_main_module();
|
||||
const auto path = self.get_path();
|
||||
|
||||
char our_directory[MAX_PATH] = {0};
|
||||
GetCurrentDirectoryA(sizeof(our_directory), our_directory);
|
||||
|
||||
|
||||
const std::string cmdline = utils::string::va("\"%s\" -proc %d", path.data(), GetCurrentProcessId());
|
||||
|
||||
steam::game_id game_id;
|
||||
game_id.raw.type = 1; // k_EGameIDTypeGameMod
|
||||
game_id.raw.app_id = app_id & 0xFFFFFF;
|
||||
|
||||
const auto* mod_id = "W3X.";
|
||||
game_id.raw.mod_id = *reinterpret_cast<const unsigned int*>(mod_id) | 0x80000000;
|
||||
|
||||
this->client_user_.invoke<bool>("SpawnProcess", self.get_path().data(), cmdline.data(), our_directory,
|
||||
&game_id.bits, title.data(), 0, 0, 0);
|
||||
}
|
||||
|
||||
void steam_proxy::clean_up_on_error()
|
||||
{
|
||||
scheduler::frame([this]()
|
||||
{
|
||||
if (this->steam_client_module_
|
||||
&& this->steam_pipe_
|
||||
&& this->global_user_
|
||||
&& this->steam_client_module_.invoke<bool>("Steam_BConnected", this->global_user_, this->steam_pipe_)
|
||||
&& this->steam_client_module_.invoke<bool>("Steam_BLoggedOn", this->global_user_, this->steam_pipe_))
|
||||
{
|
||||
return scheduler::cond_continue;
|
||||
}
|
||||
|
||||
this->client_engine_ = nullptr;
|
||||
this->client_user_ = nullptr;
|
||||
this->client_utils_ = nullptr;
|
||||
|
||||
this->steam_pipe_ = nullptr;
|
||||
this->global_user_ = nullptr;
|
||||
|
||||
this->steam_client_module_ = utils::nt::module{nullptr};
|
||||
|
||||
return scheduler::cond_end;
|
||||
});
|
||||
}
|
||||
|
||||
std::filesystem::path steam_proxy::get_steam_install_directory()
|
||||
{
|
||||
HKEY reg_key;
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\WOW6432Node\\Valve\\Steam", 0, KEY_QUERY_VALUE, ®_key) !=
|
||||
ERROR_SUCCESS)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
char path[MAX_PATH] = {0};
|
||||
DWORD length = sizeof(path);
|
||||
RegQueryValueExA(reg_key, "InstallPath", nullptr, nullptr, reinterpret_cast<BYTE*>(path),
|
||||
&length);
|
||||
RegCloseKey(reg_key);
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
REGISTER_MODULE(steam_proxy)
|
32
src/module/steam_proxy.hpp
Normal file
32
src/module/steam_proxy.hpp
Normal file
@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
#include "steam/interface.hpp"
|
||||
#include "utils/nt.hpp"
|
||||
|
||||
class steam_proxy final : public module
|
||||
{
|
||||
public:
|
||||
steam_proxy();
|
||||
|
||||
void post_load() override;
|
||||
void pre_destroy() override;
|
||||
|
||||
static std::filesystem::path get_steam_install_directory();
|
||||
|
||||
private:
|
||||
utils::nt::module steam_client_module_{};
|
||||
utils::nt::module steam_overlay_module_{};
|
||||
|
||||
steam::interface client_engine_ {};
|
||||
steam::interface client_user_ {};
|
||||
steam::interface client_utils_ {};
|
||||
|
||||
void* steam_pipe_ = nullptr;
|
||||
void* global_user_ = nullptr;
|
||||
|
||||
void run_mod() const;
|
||||
void* load_client_engine() const;
|
||||
void load_client();
|
||||
void start_mod(const std::string& title, size_t app_id);
|
||||
void clean_up_on_error();
|
||||
};
|
45
src/module/window.cpp
Normal file
45
src/module/window.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include <std_include.hpp>
|
||||
#include "window.hpp"
|
||||
#include "scheduler.hpp"
|
||||
|
||||
void window::post_load()
|
||||
{
|
||||
scheduler::frame([]()
|
||||
{
|
||||
if (const auto game_window = get_game_window())
|
||||
{
|
||||
SetWindowTextA(game_window, "Witcher 3: Online");
|
||||
return scheduler::cond_end;
|
||||
}
|
||||
|
||||
return scheduler::cond_continue;
|
||||
});
|
||||
}
|
||||
|
||||
HWND window::get_game_window()
|
||||
{
|
||||
HWND window = nullptr;
|
||||
EnumWindows(enum_windows_proc, LPARAM(&window));
|
||||
return window;
|
||||
}
|
||||
|
||||
BOOL __stdcall window::enum_windows_proc(const HWND window, const LPARAM param)
|
||||
{
|
||||
DWORD process = 0;
|
||||
GetWindowThreadProcessId(window, &process);
|
||||
|
||||
if (process == GetCurrentProcessId())
|
||||
{
|
||||
char class_name[500] = { 0 };
|
||||
GetClassNameA(window, class_name, sizeof(class_name));
|
||||
|
||||
if (class_name == "W2ViewportClass"s)
|
||||
{
|
||||
*reinterpret_cast<HWND*>(param) = window;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
REGISTER_MODULE(window);
|
16
src/module/window.hpp
Normal file
16
src/module/window.hpp
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "loader/module_loader.hpp"
|
||||
|
||||
class window final : public module
|
||||
{
|
||||
public:
|
||||
void post_load() override;
|
||||
|
||||
static HWND get_game_window();
|
||||
|
||||
private:
|
||||
std::thread thread_;
|
||||
bool kill_ = false;
|
||||
|
||||
static BOOL __stdcall enum_windows_proc(HWND window, LPARAM param);
|
||||
};
|
8
src/proto/test.proto
Normal file
8
src/proto/test.proto
Normal file
@ -0,0 +1,8 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package proto.test;
|
||||
|
||||
message lul
|
||||
{
|
||||
bytes lulul = 1;
|
||||
}
|
@ -1 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define IMAGE_SPLASH 300
|
||||
|
@ -61,13 +61,13 @@ BEGIN
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "IW4x"
|
||||
VALUE "FileDescription", "IW4x²"
|
||||
VALUE "CompanyName", "momo5502 & RektInator"
|
||||
VALUE "FileDescription", "Witcher 3: Online"
|
||||
VALUE "FileVersion", "1.0.0.0"
|
||||
VALUE "InternalName", "IW4x²"
|
||||
VALUE "InternalName", "Witcher 3: Online"
|
||||
VALUE "LegalCopyright", "All rights reserved."
|
||||
VALUE "OriginalFilename", "iw4x².exe"
|
||||
VALUE "ProductName", "iw4x²"
|
||||
VALUE "OriginalFilename", "w3x.exe"
|
||||
VALUE "ProductName", "w3x"
|
||||
VALUE "ProductVersion", "1.0.0.0"
|
||||
END
|
||||
END
|
||||
@ -82,7 +82,9 @@ END
|
||||
// Binary Data
|
||||
//
|
||||
|
||||
102 ICON "resources/icon.ico"
|
||||
102 ICON "resources/icon_dark.ico"
|
||||
|
||||
IMAGE_SPLASH BITMAP "resources/splash.bmp"
|
||||
|
||||
|
||||
#endif // English (United States) resources
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 352 KiB After Width: | Height: | Size: 115 KiB |
BIN
src/resources/icon_dark.ico
Normal file
BIN
src/resources/icon_dark.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 113 KiB |
BIN
src/resources/splash.bmp
Normal file
BIN
src/resources/splash.bmp
Normal file
Binary file not shown.
After Width: | Height: | Size: 972 KiB |
@ -1 +1,10 @@
|
||||
#include <std_include.hpp>
|
||||
|
||||
#pragma comment(linker, "/stack:0x2000000")
|
||||
#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language=''\"")
|
||||
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllexport) DWORD NvOptimusEnablement = 1;
|
||||
__declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 1;
|
||||
};
|
||||
|
@ -1,30 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#define TLS_PAYLOAD_SIZE 0x2000
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4127)
|
||||
#pragma warning(disable: 4244)
|
||||
#pragma warning(disable: 4458)
|
||||
#pragma warning(disable: 4702)
|
||||
#pragma warning(disable: 4996)
|
||||
#pragma warning(disable: 5054)
|
||||
#pragma warning(disable: 6011)
|
||||
#pragma warning(disable: 6297)
|
||||
#pragma warning(disable: 6385)
|
||||
#pragma warning(disable: 6386)
|
||||
#pragma warning(disable: 6387)
|
||||
#pragma warning(disable: 26110)
|
||||
#pragma warning(disable: 26451)
|
||||
#pragma warning(disable: 26444)
|
||||
#pragma warning(disable: 26451)
|
||||
#pragma warning(disable: 26489)
|
||||
#pragma warning(disable: 26495)
|
||||
#pragma warning(disable: 26498)
|
||||
#pragma warning(disable: 26812)
|
||||
#pragma warning(disable: 28020)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <windows.h>
|
||||
#include <mshtml.h>
|
||||
#include <mshtmhst.h>
|
||||
#include <ExDisp.h>
|
||||
#include <WinSock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <corecrt_io.h>
|
||||
#include <fcntl.h>
|
||||
#include <shellapi.h>
|
||||
#include <csetjmp>
|
||||
#include <Windows.h>
|
||||
#include <ShlObj.h>
|
||||
|
||||
// min and max is required by gdi, therefore NOMINMAX won't work
|
||||
#ifdef max
|
||||
@ -46,7 +49,25 @@
|
||||
#include <fstream>
|
||||
#include <utility>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
|
||||
#include <gsl/gsl>
|
||||
#include <udis86.h>
|
||||
#include <MinHook.h>
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
#include <rapidjson/stringbuffer.h>
|
||||
|
||||
#include <asmjit/core/jitruntime.h>
|
||||
#include <asmjit/x86/x86assembler.h>
|
||||
|
||||
#include "proto/test.pb.h"
|
||||
|
||||
#pragma warning(pop)
|
||||
|
||||
#include "resource.hpp"
|
||||
|
||||
using namespace std::literals;
|
||||
|
||||
extern __declspec(thread) char tls_data[TLS_PAYLOAD_SIZE];
|
||||
|
121
src/steam/interface.cpp
Normal file
121
src/steam/interface.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include <std_include.hpp>
|
||||
#include "interface.hpp"
|
||||
#include "utils/memory.hpp"
|
||||
#include "utils/nt.hpp"
|
||||
|
||||
namespace steam
|
||||
{
|
||||
interface::interface() : interface(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
interface::interface(void* interface_ptr) : interface_ptr_(static_cast<void***>(interface_ptr))
|
||||
{
|
||||
}
|
||||
|
||||
interface::operator bool() const
|
||||
{
|
||||
return this->interface_ptr_ != nullptr;
|
||||
}
|
||||
|
||||
void* interface::find_method(const std::string& name)
|
||||
{
|
||||
const auto method_entry = this->methods_.find(name);
|
||||
if (method_entry != this->methods_.end())
|
||||
{
|
||||
return method_entry->second;
|
||||
}
|
||||
|
||||
return this->search_method(name);
|
||||
}
|
||||
|
||||
void* interface::search_method(const std::string& name)
|
||||
{
|
||||
if (!utils::memory::is_bad_read_ptr(this->interface_ptr_))
|
||||
{
|
||||
auto vftbl = *this->interface_ptr_;
|
||||
|
||||
while (!utils::memory::is_bad_read_ptr(vftbl) && !utils::memory::is_bad_code_ptr(*vftbl))
|
||||
{
|
||||
const auto ptr = *vftbl;
|
||||
const auto result = this->analyze_method(ptr);
|
||||
if (!result.empty())
|
||||
{
|
||||
this->methods_[result] = ptr;
|
||||
|
||||
if (result == name)
|
||||
{
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
++vftbl;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string interface::analyze_method(const void* method_ptr)
|
||||
{
|
||||
if (utils::memory::is_bad_code_ptr(method_ptr)) return {};
|
||||
|
||||
ud_t ud;
|
||||
ud_init(&ud);
|
||||
ud_set_mode(&ud, 64);
|
||||
ud_set_pc(&ud, uint64_t(method_ptr));
|
||||
ud_set_input_buffer(&ud, static_cast<const uint8_t*>(method_ptr), INT32_MAX);
|
||||
|
||||
while (true)
|
||||
{
|
||||
ud_disassemble(&ud);
|
||||
|
||||
if (ud_insn_mnemonic(&ud) == UD_Iret)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (ud_insn_mnemonic(&ud) == UD_Ilea)
|
||||
{
|
||||
const auto* operand = ud_insn_opr(&ud, 1);
|
||||
if (operand && operand->type == UD_OP_MEM && operand->base == UD_R_RIP)
|
||||
{
|
||||
auto* operand_ptr = reinterpret_cast<char*>(ud_insn_len(&ud) + ud_insn_off(&ud) + operand->lval.sdword);
|
||||
if (!utils::memory::is_bad_read_ptr(operand_ptr) && this->is_rdata(operand_ptr))
|
||||
{
|
||||
return operand_ptr;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (*reinterpret_cast<unsigned char*>(ud.pc) == 0xCC) break; // int 3
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool interface::is_rdata(void* pointer)
|
||||
{
|
||||
const auto pointer_lib = utils::nt::module::get_by_address(pointer);
|
||||
|
||||
for (const auto& section : pointer_lib.get_section_headers())
|
||||
{
|
||||
const auto size = sizeof(section->Name);
|
||||
char name[size + 1];
|
||||
name[size] = 0;
|
||||
std::memcpy(name, section->Name, size);
|
||||
|
||||
if (name == ".rdata"s)
|
||||
{
|
||||
const auto target = size_t(pointer);
|
||||
const size_t source_start = size_t(pointer_lib.get_ptr()) + section->PointerToRawData;
|
||||
const size_t source_end = source_start + section->SizeOfRawData;
|
||||
|
||||
return target >= source_start && target <= source_end;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
86
src/steam/interface.hpp
Normal file
86
src/steam/interface.hpp
Normal file
@ -0,0 +1,86 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef interface
|
||||
#undef interface
|
||||
#endif
|
||||
|
||||
namespace steam
|
||||
{
|
||||
struct raw_steam_id final
|
||||
{
|
||||
unsigned int account_id : 32;
|
||||
unsigned int account_instance : 20;
|
||||
unsigned int account_type : 4;
|
||||
int universe : 8;
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
raw_steam_id raw;
|
||||
unsigned long long bits;
|
||||
} steam_id;
|
||||
|
||||
#pragma pack( push, 1 )
|
||||
struct raw_game_id final
|
||||
{
|
||||
unsigned int app_id : 24;
|
||||
unsigned int type : 8;
|
||||
unsigned int mod_id : 32;
|
||||
};
|
||||
|
||||
typedef union
|
||||
{
|
||||
raw_game_id raw;
|
||||
unsigned long long bits;
|
||||
} game_id;
|
||||
#pragma pack( pop )
|
||||
|
||||
class interface final
|
||||
{
|
||||
public:
|
||||
|
||||
interface();
|
||||
interface(void* interface_ptr);
|
||||
|
||||
operator bool() const;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke(const std::string& method_name, Args ... args)
|
||||
{
|
||||
if (!this->interface_ptr_)
|
||||
{
|
||||
throw std::runtime_error("Invalid interface pointer");
|
||||
}
|
||||
|
||||
const auto method = this->find_method(method_name);
|
||||
if (!method)
|
||||
{
|
||||
throw std::runtime_error("Unable to find desired method");
|
||||
}
|
||||
|
||||
return static_cast<T(__thiscall*)(void*, Args ...)>(method)(this->interface_ptr_, args...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke(const size_t table_entry, Args ... args)
|
||||
{
|
||||
if (!this->interface_ptr_)
|
||||
{
|
||||
throw std::runtime_error("Invalid interface pointer");
|
||||
}
|
||||
|
||||
return static_cast<T(__thiscall*)(void*, Args ...)>((*this->interface_ptr_)[table_entry])(this->interface_ptr_, args...);
|
||||
}
|
||||
|
||||
private:
|
||||
void*** interface_ptr_;
|
||||
std::unordered_map<std::string, void*> methods_;
|
||||
|
||||
void* find_method(const std::string& name);
|
||||
void* search_method(const std::string& name);
|
||||
|
||||
std::string analyze_method(const void* method_ptr);
|
||||
|
||||
bool is_rdata(void* pointer);
|
||||
};
|
||||
}
|
119
src/utils/com.cpp
Normal file
119
src/utils/com.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include <std_include.hpp>
|
||||
#include "com.hpp"
|
||||
|
||||
namespace utils::com
|
||||
{
|
||||
namespace
|
||||
{
|
||||
[[maybe_unused]] class _
|
||||
{
|
||||
public:
|
||||
_()
|
||||
{
|
||||
if(FAILED(CoInitialize(nullptr)))
|
||||
{
|
||||
throw std::runtime_error("Failed to initialize the component object model");
|
||||
}
|
||||
}
|
||||
|
||||
~_()
|
||||
{
|
||||
CoUninitialize();
|
||||
}
|
||||
} __;
|
||||
}
|
||||
|
||||
bool select_folder(std::string& out_folder, const std::string& title, const std::string& selected_folder)
|
||||
{
|
||||
IFileOpenDialog* file_dialog = nullptr;
|
||||
if(FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&file_dialog))))
|
||||
{
|
||||
throw std::runtime_error("Failed to create co instance");
|
||||
}
|
||||
|
||||
const auto $1 = gsl::finally([file_dialog]()
|
||||
{
|
||||
file_dialog->Release();
|
||||
});
|
||||
|
||||
DWORD dw_options;
|
||||
if(FAILED(file_dialog->GetOptions(&dw_options)))
|
||||
{
|
||||
throw std::runtime_error("Failed to get options");
|
||||
}
|
||||
|
||||
if(FAILED(file_dialog->SetOptions(dw_options | FOS_PICKFOLDERS)))
|
||||
{
|
||||
throw std::runtime_error("Failed to set options");
|
||||
}
|
||||
|
||||
std::wstring wide_title(title.begin(), title.end());
|
||||
if(FAILED(file_dialog->SetTitle(wide_title.data())))
|
||||
{
|
||||
throw std::runtime_error("Failed to set title");
|
||||
}
|
||||
|
||||
if (!selected_folder.empty())
|
||||
{
|
||||
file_dialog->ClearClientData();
|
||||
|
||||
std::wstring wide_selected_folder(selected_folder.begin(), selected_folder.end());
|
||||
for (auto& chr : wide_selected_folder)
|
||||
{
|
||||
if (chr == L'/')
|
||||
{
|
||||
chr = L'\\';
|
||||
}
|
||||
}
|
||||
|
||||
IShellItem* shell_item = nullptr;
|
||||
if(FAILED(SHCreateItemFromParsingName(wide_selected_folder.data(), NULL, IID_PPV_ARGS(&shell_item))))
|
||||
{
|
||||
throw std::runtime_error("Failed to create item from parsing name");
|
||||
}
|
||||
|
||||
if (FAILED(file_dialog->SetDefaultFolder(shell_item)))
|
||||
{
|
||||
throw std::runtime_error("Failed to set default folder");
|
||||
}
|
||||
}
|
||||
|
||||
const auto result = file_dialog->Show(nullptr);
|
||||
if(result == HRESULT_FROM_WIN32(ERROR_CANCELLED))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (FAILED(result))
|
||||
{
|
||||
throw std::runtime_error("Failed to show dialog");
|
||||
}
|
||||
|
||||
IShellItem* result_item = nullptr;
|
||||
if(FAILED(file_dialog->GetResult(&result_item)))
|
||||
{
|
||||
throw std::runtime_error("Failed to get result");
|
||||
}
|
||||
|
||||
const auto $2 = gsl::finally([result_item]()
|
||||
{
|
||||
result_item->Release();
|
||||
});
|
||||
|
||||
PWSTR raw_path = nullptr;
|
||||
if(FAILED(result_item->GetDisplayName(SIGDN_FILESYSPATH, &raw_path)))
|
||||
{
|
||||
throw std::runtime_error("Failed to get path display name");
|
||||
}
|
||||
|
||||
const auto $3 = gsl::finally([raw_path]()
|
||||
{
|
||||
CoTaskMemFree(raw_path);
|
||||
});
|
||||
|
||||
std::wstring result_path = raw_path;
|
||||
out_folder = std::string(result_path.begin(), result_path.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
6
src/utils/com.hpp
Normal file
6
src/utils/com.hpp
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils::com
|
||||
{
|
||||
bool select_folder(std::string& out_folder, const std::string& title = "Select a Folder", const std::string& selected_folder = {});
|
||||
}
|
131
src/utils/concurrent_list.hpp
Normal file
131
src/utils/concurrent_list.hpp
Normal file
@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
{
|
||||
template <typename T>
|
||||
class concurrent_list final
|
||||
{
|
||||
public:
|
||||
class element final
|
||||
{
|
||||
public:
|
||||
explicit element(std::recursive_mutex* mutex, std::shared_ptr<T> entry = {},
|
||||
std::shared_ptr<element> next = {}) :
|
||||
mutex_(mutex),
|
||||
entry_(std::move(entry)),
|
||||
next_(std::move(next))
|
||||
{
|
||||
}
|
||||
|
||||
void remove(const std::shared_ptr<T>& element)
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
if (!this->next_) return;
|
||||
|
||||
if (this->next_->entry_.get() == element.get())
|
||||
{
|
||||
this->next_ = this->next_->next_;
|
||||
}
|
||||
else
|
||||
{
|
||||
this->next_->remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::shared_ptr<element> get_next() const
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
return this->next_;
|
||||
}
|
||||
|
||||
std::shared_ptr<T> operator*() const
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
return this->entry_;
|
||||
}
|
||||
|
||||
element& operator++()
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
*this = this->next_ ? *this->next_ : element(this->mutex_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
element operator++(int)
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
auto result = *this;
|
||||
this->operator++();
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator==(const element& other)
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
return this->entry_.get() == other.entry_.get();
|
||||
}
|
||||
|
||||
bool operator!=(const element& other)
|
||||
{
|
||||
std::lock_guard _(*this->mutex_);
|
||||
return !(*this == other);
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex* mutex_;
|
||||
std::shared_ptr<T> entry_;
|
||||
std::shared_ptr<element> next_;
|
||||
};
|
||||
|
||||
element begin()
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
return this->entry_ ? *this->entry_ : this->end();
|
||||
}
|
||||
|
||||
element end()
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
return element(&this->mutex_);
|
||||
}
|
||||
|
||||
void remove(const element& entry)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
this->remove(*entry);
|
||||
}
|
||||
|
||||
void remove(const std::shared_ptr<T>& element)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
if (!this->entry_) return;
|
||||
|
||||
if ((**this->entry_).get() == element.get())
|
||||
{
|
||||
this->entry_ = this->entry_->get_next();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->entry_->remove(element);
|
||||
}
|
||||
}
|
||||
|
||||
void add(const T& object)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
const auto object_ptr = std::make_shared<T>(object);
|
||||
this->entry_ = std::make_shared<element>(&this->mutex_, object_ptr, this->entry_);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
this->entry_ = {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::recursive_mutex mutex_;
|
||||
std::shared_ptr<element> entry_;
|
||||
};
|
||||
}
|
147
src/utils/hook.cpp
Normal file
147
src/utils/hook.cpp
Normal file
@ -0,0 +1,147 @@
|
||||
#include <std_include.hpp>
|
||||
#include "hook.hpp"
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils::hook
|
||||
{
|
||||
namespace
|
||||
{
|
||||
[[maybe_unused]] class _
|
||||
{
|
||||
public:
|
||||
_()
|
||||
{
|
||||
if(MH_Initialize() != MH_OK)
|
||||
{
|
||||
throw std::runtime_error("Failed to initialize MinHook");
|
||||
}
|
||||
}
|
||||
|
||||
~_()
|
||||
{
|
||||
MH_Uninitialize();
|
||||
}
|
||||
} __;
|
||||
}
|
||||
|
||||
detour::detour(const size_t place, void* target) : detour(reinterpret_cast<void*>(place), target)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
detour::detour(void* place, void* target) : place_(place)
|
||||
{
|
||||
if (MH_CreateHook(this->place_, target, &this->original_) != MH_OK)
|
||||
{
|
||||
throw std::runtime_error(string::va("Unable to create hook at location: %p", this->place_));
|
||||
}
|
||||
|
||||
this->enable();
|
||||
}
|
||||
|
||||
detour::~detour()
|
||||
{
|
||||
if (this->place_)
|
||||
{
|
||||
MH_RemoveHook(this->place_);
|
||||
}
|
||||
|
||||
this->place_ = nullptr;
|
||||
this->original_ = nullptr;
|
||||
}
|
||||
|
||||
void detour::enable() const
|
||||
{
|
||||
MH_EnableHook(this->place_);
|
||||
}
|
||||
|
||||
void detour::disable() const
|
||||
{
|
||||
MH_DisableHook(this->place_);
|
||||
}
|
||||
|
||||
void* detour::get_original() const
|
||||
{
|
||||
return this->original_;
|
||||
}
|
||||
|
||||
void nop(void* place, const size_t length)
|
||||
{
|
||||
DWORD old_protect{};
|
||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
|
||||
std::memset(place, 0x90, length);
|
||||
|
||||
VirtualProtect(place, length, old_protect, &old_protect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, length);
|
||||
}
|
||||
|
||||
void nop(const size_t place, const size_t length)
|
||||
{
|
||||
nop(reinterpret_cast<void*>(place), length);
|
||||
}
|
||||
|
||||
void copy(void* place, const void* data, const size_t length)
|
||||
{
|
||||
DWORD old_protect{};
|
||||
VirtualProtect(place, length, PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
|
||||
std::memmove(place, data, length);
|
||||
|
||||
VirtualProtect(place, length, old_protect, &old_protect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, length);
|
||||
}
|
||||
|
||||
void copy(const size_t place, const void* data, const size_t length)
|
||||
{
|
||||
copy(reinterpret_cast<void*>(place), data, length);
|
||||
}
|
||||
|
||||
void jump(void* pointer, void* data)
|
||||
{
|
||||
static const unsigned char jump_data[] = { 0x48, 0xb8, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xff, 0xe0 };
|
||||
|
||||
auto* patch_pointer = PBYTE(pointer);
|
||||
|
||||
DWORD old_protect{};
|
||||
VirtualProtect(patch_pointer, sizeof(jump_data), PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
|
||||
std::memmove(patch_pointer, jump_data, sizeof(jump_data));
|
||||
std::memmove(patch_pointer + 2, &data, sizeof(data));
|
||||
|
||||
VirtualProtect(patch_pointer, sizeof(jump_data), old_protect, &old_protect);
|
||||
}
|
||||
|
||||
void jump(const size_t pointer, void* data)
|
||||
{
|
||||
return jump(reinterpret_cast<void*>(pointer), data);
|
||||
}
|
||||
|
||||
void* assemble(const std::function<void(assembler&)>& asm_function)
|
||||
{
|
||||
static asmjit::JitRuntime runtime;
|
||||
|
||||
asmjit::CodeHolder code;
|
||||
code.init(runtime.environment());
|
||||
|
||||
assembler a(&code);
|
||||
|
||||
asm_function(a);
|
||||
|
||||
void* result = nullptr;
|
||||
runtime.add(&result, &code);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void* follow_branch(void* address)
|
||||
{
|
||||
auto* const data = static_cast<uint8_t*>(address);
|
||||
if(*data != 0xE8 && *data != 0xE9)
|
||||
{
|
||||
throw std::runtime_error("No branch instruction found");
|
||||
}
|
||||
|
||||
return extract<void*>(data + 1);
|
||||
}
|
||||
}
|
158
src/utils/hook.hpp
Normal file
158
src/utils/hook.hpp
Normal file
@ -0,0 +1,158 @@
|
||||
#pragma once
|
||||
#include "signature.hpp"
|
||||
|
||||
using namespace asmjit::x86;
|
||||
|
||||
namespace utils::hook
|
||||
{
|
||||
class assembler : public Assembler
|
||||
{
|
||||
public:
|
||||
using Assembler::Assembler;
|
||||
using Assembler::call;
|
||||
using Assembler::jmp;
|
||||
|
||||
void pushad64()
|
||||
{
|
||||
this->push(rax);
|
||||
this->push(rcx);
|
||||
this->push(rdx);
|
||||
this->push(rbx);
|
||||
this->push(rsp);
|
||||
this->push(rbp);
|
||||
this->push(rsi);
|
||||
this->push(rdi);
|
||||
|
||||
this->sub(rsp, 0x40);
|
||||
}
|
||||
|
||||
void popad64()
|
||||
{
|
||||
this->add(rsp, 0x40);
|
||||
|
||||
this->pop(rdi);
|
||||
this->pop(rsi);
|
||||
this->pop(rbp);
|
||||
this->pop(rsp);
|
||||
this->pop(rbx);
|
||||
this->pop(rdx);
|
||||
this->pop(rcx);
|
||||
this->pop(rax);
|
||||
}
|
||||
|
||||
asmjit::Error call(void* target)
|
||||
{
|
||||
return Assembler::call(size_t(target));
|
||||
}
|
||||
|
||||
asmjit::Error jmp(void* target)
|
||||
{
|
||||
return Assembler::jmp(size_t(target));
|
||||
}
|
||||
};
|
||||
|
||||
class detour
|
||||
{
|
||||
public:
|
||||
detour() = default;
|
||||
detour(void* place, void* target);
|
||||
detour(size_t place, void* target);
|
||||
~detour();
|
||||
|
||||
detour(detour&& other) noexcept
|
||||
{
|
||||
this->operator=(std::move(other));
|
||||
}
|
||||
|
||||
detour& operator= (detour&& other) noexcept
|
||||
{
|
||||
if(this != &other)
|
||||
{
|
||||
this->~detour();
|
||||
|
||||
this->place_ = other.place_;
|
||||
this->original_ = other.original_;
|
||||
|
||||
other.place_ = nullptr;
|
||||
other.original_ = nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
detour(const detour&) = delete;
|
||||
detour& operator= (const detour&) = delete;
|
||||
|
||||
void enable() const;
|
||||
void disable() const;
|
||||
|
||||
template <typename T>
|
||||
T* get() const
|
||||
{
|
||||
return static_cast<T*>(this->get_original());
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke(Args... args)
|
||||
{
|
||||
return static_cast<T(*)(Args ...)>(this->get_original())(args...);
|
||||
}
|
||||
|
||||
[[nodiscard]] void* get_original() const;
|
||||
|
||||
private:
|
||||
void* place_{};
|
||||
void* original_{};
|
||||
};
|
||||
|
||||
void nop(void* place, size_t length);
|
||||
void nop(size_t place, size_t length);
|
||||
|
||||
void copy(void* place, const void* data, size_t length);
|
||||
void copy(size_t place, const void* data, size_t length);
|
||||
|
||||
void jump(void* pointer, void* data);
|
||||
void jump(size_t pointer, void* data);
|
||||
|
||||
void* assemble(const std::function<void(assembler&)>& asm_function);
|
||||
|
||||
template <typename T>
|
||||
T extract(void* address)
|
||||
{
|
||||
const auto data = static_cast<uint8_t*>(address);
|
||||
const auto offset = *reinterpret_cast<int32_t*>(data);
|
||||
return reinterpret_cast<T>(data + offset + 4);
|
||||
}
|
||||
|
||||
void* follow_branch(void* address);
|
||||
|
||||
template <typename T>
|
||||
static void set(void* place, T value)
|
||||
{
|
||||
DWORD old_protect;
|
||||
VirtualProtect(place, sizeof(T), PAGE_EXECUTE_READWRITE, &old_protect);
|
||||
|
||||
*static_cast<T*>(place) = value;
|
||||
|
||||
VirtualProtect(place, sizeof(T), old_protect, &old_protect);
|
||||
FlushInstructionCache(GetCurrentProcess(), place, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void set(const size_t place, T value)
|
||||
{
|
||||
return set<T>(reinterpret_cast<void*>(place), value);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static T invoke(size_t func, Args... args)
|
||||
{
|
||||
return reinterpret_cast<T(*)(Args ...)>(func)(args...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static T invoke(void* func, Args... args)
|
||||
{
|
||||
return static_cast<T(*)(Args ...)>(func)(args...);
|
||||
}
|
||||
}
|
112
src/utils/io.cpp
Normal file
112
src/utils/io.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
#include <std_include.hpp>
|
||||
#include "io.hpp"
|
||||
|
||||
namespace utils::io
|
||||
{
|
||||
bool file_exists(const std::string& file)
|
||||
{
|
||||
return std::ifstream(file).good();
|
||||
}
|
||||
|
||||
bool write_file(const std::string& file, const std::string& data, const bool append)
|
||||
{
|
||||
const auto pos = file.find_last_of("/\\");
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
create_directory(file.substr(0, pos));
|
||||
}
|
||||
|
||||
std::ofstream stream(
|
||||
file, std::ios::binary | std::ofstream::out | (append ? std::ofstream::app : 0));
|
||||
|
||||
if (stream.is_open())
|
||||
{
|
||||
stream.write(data.data(), data.size());
|
||||
stream.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string read_file(const std::string& file)
|
||||
{
|
||||
std::string data;
|
||||
read_file(file, &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool read_file(const std::string& file, std::string* data)
|
||||
{
|
||||
if (!data) return false;
|
||||
data->clear();
|
||||
|
||||
if (file_exists(file))
|
||||
{
|
||||
std::ifstream stream(file, std::ios::binary);
|
||||
if (!stream.is_open()) return false;
|
||||
|
||||
stream.seekg(0, std::ios::end);
|
||||
const std::streamsize size = stream.tellg();
|
||||
stream.seekg(0, std::ios::beg);
|
||||
|
||||
if (size > -1)
|
||||
{
|
||||
data->resize(static_cast<uint32_t>(size));
|
||||
stream.read(const_cast<char*>(data->data()), size);
|
||||
stream.close();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t file_size(const std::string& file)
|
||||
{
|
||||
if (file_exists(file))
|
||||
{
|
||||
std::ifstream stream(file, std::ios::binary);
|
||||
|
||||
if (stream.good())
|
||||
{
|
||||
stream.seekg(0, std::ios::end);
|
||||
return static_cast<size_t>(stream.tellg());
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool create_directory(const std::string& directory)
|
||||
{
|
||||
return std::filesystem::create_directories(directory);
|
||||
}
|
||||
|
||||
bool directory_exists(const std::string& directory)
|
||||
{
|
||||
return std::filesystem::is_directory(directory);
|
||||
}
|
||||
|
||||
bool directory_is_empty(const std::string& directory)
|
||||
{
|
||||
return std::filesystem::is_empty(directory);
|
||||
}
|
||||
|
||||
std::vector<std::string> list_files(const std::string& directory)
|
||||
{
|
||||
std::vector<std::string> files;
|
||||
|
||||
for (auto& file : std::filesystem::directory_iterator(directory))
|
||||
{
|
||||
files.push_back(file.path().generic_string());
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target)
|
||||
{
|
||||
std::filesystem::copy(src, target, std::filesystem::copy_options::overwrite_existing | std::filesystem::copy_options::recursive);
|
||||
}
|
||||
}
|
15
src/utils/io.hpp
Normal file
15
src/utils/io.hpp
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils::io
|
||||
{
|
||||
bool file_exists(const std::string& file);
|
||||
bool write_file(const std::string& file, const std::string& data, bool append = false);
|
||||
bool read_file(const std::string& file, std::string* data);
|
||||
std::string read_file(const std::string& file);
|
||||
size_t file_size(const std::string& file);
|
||||
bool create_directory(const std::string& directory);
|
||||
bool directory_exists(const std::string& directory);
|
||||
bool directory_is_empty(const std::string& directory);
|
||||
std::vector<std::string> list_files(const std::string& directory);
|
||||
void copy_folder(const std::filesystem::path& src, const std::filesystem::path& target);
|
||||
}
|
140
src/utils/memory.cpp
Normal file
140
src/utils/memory.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
#include <std_include.hpp>
|
||||
#include "memory.hpp"
|
||||
|
||||
namespace utils
|
||||
{
|
||||
memory::allocator memory::mem_allocator_;
|
||||
|
||||
memory::allocator::~allocator()
|
||||
{
|
||||
this->clear();
|
||||
}
|
||||
|
||||
void memory::allocator::clear()
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
for (auto& data : this->pool_)
|
||||
{
|
||||
memory::free(data);
|
||||
}
|
||||
|
||||
this->pool_.clear();
|
||||
}
|
||||
|
||||
void memory::allocator::free(void* data)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
const auto j = std::find(this->pool_.begin(), this->pool_.end(), data);
|
||||
if (j != this->pool_.end())
|
||||
{
|
||||
memory::free(data);
|
||||
this->pool_.erase(j);
|
||||
}
|
||||
}
|
||||
|
||||
void memory::allocator::free(const void* data)
|
||||
{
|
||||
this->free(const_cast<void*>(data));
|
||||
}
|
||||
|
||||
void* memory::allocator::allocate(const size_t length)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
const auto data = memory::allocate(length);
|
||||
this->pool_.push_back(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool memory::allocator::empty() const
|
||||
{
|
||||
return this->pool_.empty();
|
||||
}
|
||||
|
||||
char* memory::allocator::duplicate_string(const std::string& string)
|
||||
{
|
||||
std::lock_guard _(this->mutex_);
|
||||
|
||||
const auto data = memory::duplicate_string(string);
|
||||
this->pool_.push_back(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
void* memory::allocate(const size_t length)
|
||||
{
|
||||
return calloc(length, 1);
|
||||
}
|
||||
|
||||
char* memory::duplicate_string(const std::string& string)
|
||||
{
|
||||
const auto new_string = allocate_array<char>(string.size() + 1);
|
||||
std::memcpy(new_string, string.data(), string.size());
|
||||
return new_string;
|
||||
}
|
||||
|
||||
void memory::free(void* data)
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
::free(data);
|
||||
}
|
||||
}
|
||||
|
||||
void memory::free(const void* data)
|
||||
{
|
||||
free(const_cast<void*>(data));
|
||||
}
|
||||
|
||||
bool memory::is_set(const void* mem, const char chr, const size_t length)
|
||||
{
|
||||
const auto mem_arr = static_cast<const char*>(mem);
|
||||
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
{
|
||||
if (mem_arr[i] != chr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool memory::is_bad_read_ptr(const void* ptr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi = {};
|
||||
if (VirtualQuery(ptr, &mbi, sizeof(mbi)))
|
||||
{
|
||||
const DWORD mask = (PAGE_READONLY | PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READ |
|
||||
PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY);
|
||||
auto b = !(mbi.Protect & mask);
|
||||
// check the page is not a guard page
|
||||
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true;
|
||||
|
||||
return b;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool memory::is_bad_code_ptr(const void* ptr)
|
||||
{
|
||||
MEMORY_BASIC_INFORMATION mbi = {};
|
||||
if (VirtualQuery(ptr, &mbi, sizeof(mbi)))
|
||||
{
|
||||
const DWORD mask = (PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY);
|
||||
auto b = !(mbi.Protect & mask);
|
||||
// check the page is not a guard page
|
||||
if (mbi.Protect & (PAGE_GUARD | PAGE_NOACCESS)) b = true;
|
||||
|
||||
return b;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
memory::allocator* memory::get_allocator()
|
||||
{
|
||||
return &memory::mem_allocator_;
|
||||
}
|
||||
}
|
71
src/utils/memory.hpp
Normal file
71
src/utils/memory.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils
|
||||
{
|
||||
class memory final
|
||||
{
|
||||
public:
|
||||
class allocator final
|
||||
{
|
||||
public:
|
||||
~allocator();
|
||||
|
||||
void clear();
|
||||
|
||||
void free(void* data);
|
||||
|
||||
void free(const void* data);
|
||||
|
||||
void* allocate(size_t length);
|
||||
|
||||
template <typename T>
|
||||
inline T* allocate()
|
||||
{
|
||||
return this->allocate_array<T>(1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline T* allocate_array(const size_t count = 1)
|
||||
{
|
||||
return static_cast<T*>(this->allocate(count * sizeof(T)));
|
||||
}
|
||||
|
||||
bool empty() const;
|
||||
|
||||
char* duplicate_string(const std::string& string);
|
||||
|
||||
private:
|
||||
std::mutex mutex_;
|
||||
std::vector<void*> pool_;
|
||||
};
|
||||
|
||||
static void* allocate(size_t length);
|
||||
|
||||
template <typename T>
|
||||
static inline T* allocate()
|
||||
{
|
||||
return allocate_array<T>(1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T* allocate_array(const size_t count = 1)
|
||||
{
|
||||
return static_cast<T*>(allocate(count * sizeof(T)));
|
||||
}
|
||||
|
||||
static char* duplicate_string(const std::string& string);
|
||||
|
||||
static void free(void* data);
|
||||
static void free(const void* data);
|
||||
|
||||
static bool is_set(const void* mem, char chr, size_t length);
|
||||
|
||||
static bool is_bad_read_ptr(const void* ptr);
|
||||
static bool is_bad_code_ptr(const void* ptr);
|
||||
|
||||
static allocator* get_allocator();
|
||||
|
||||
private:
|
||||
static allocator mem_allocator_;
|
||||
};
|
||||
}
|
217
src/utils/nt.cpp
Normal file
217
src/utils/nt.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
#include <std_include.hpp>
|
||||
#include "nt.hpp"
|
||||
|
||||
namespace utils::nt
|
||||
{
|
||||
module module::load(const std::string& name)
|
||||
{
|
||||
return module(LoadLibraryA(name.data()));
|
||||
}
|
||||
|
||||
module module::load(const std::filesystem::path& path)
|
||||
{
|
||||
return module::load(path.generic_string());
|
||||
}
|
||||
|
||||
module module::get_by_address(void* address)
|
||||
{
|
||||
HMODULE handle = nullptr;
|
||||
GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCSTR>(address), &handle);
|
||||
return module(handle);
|
||||
}
|
||||
|
||||
module::module()
|
||||
{
|
||||
this->module_ = GetModuleHandleA(nullptr);
|
||||
}
|
||||
|
||||
module::module(const std::string& name)
|
||||
{
|
||||
this->module_ = GetModuleHandleA(name.data());
|
||||
}
|
||||
|
||||
module::module(const HMODULE handle)
|
||||
{
|
||||
this->module_ = handle;
|
||||
}
|
||||
|
||||
bool module::operator==(const module& obj) const
|
||||
{
|
||||
return this->module_ == obj.module_;
|
||||
}
|
||||
|
||||
module::operator bool() const
|
||||
{
|
||||
return this->is_valid();
|
||||
}
|
||||
|
||||
module::operator HMODULE() const
|
||||
{
|
||||
return this->get_handle();
|
||||
}
|
||||
|
||||
PIMAGE_NT_HEADERS module::get_nt_headers() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return reinterpret_cast<PIMAGE_NT_HEADERS>(this->get_ptr() + this->get_dos_header()->e_lfanew);
|
||||
}
|
||||
|
||||
PIMAGE_DOS_HEADER module::get_dos_header() const
|
||||
{
|
||||
return reinterpret_cast<PIMAGE_DOS_HEADER>(this->get_ptr());
|
||||
}
|
||||
|
||||
PIMAGE_OPTIONAL_HEADER module::get_optional_header() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return &this->get_nt_headers()->OptionalHeader;
|
||||
}
|
||||
|
||||
std::vector<PIMAGE_SECTION_HEADER> module::get_section_headers() const
|
||||
{
|
||||
std::vector<PIMAGE_SECTION_HEADER> headers;
|
||||
|
||||
auto nt_headers = this->get_nt_headers();
|
||||
auto section = IMAGE_FIRST_SECTION(nt_headers);
|
||||
|
||||
for (uint16_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i, ++section)
|
||||
{
|
||||
if (section) headers.push_back(section);
|
||||
else OutputDebugStringA("There was an invalid section :O");
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
std::uint8_t* module::get_ptr() const
|
||||
{
|
||||
return reinterpret_cast<std::uint8_t*>(this->module_);
|
||||
}
|
||||
|
||||
void module::unprotect() const
|
||||
{
|
||||
if (!this->is_valid()) return;
|
||||
|
||||
DWORD protection;
|
||||
VirtualProtect(this->get_ptr(), this->get_optional_header()->SizeOfImage, PAGE_EXECUTE_READWRITE,
|
||||
&protection);
|
||||
}
|
||||
|
||||
size_t module::get_relative_entry_point() const
|
||||
{
|
||||
if (!this->is_valid()) return 0;
|
||||
return this->get_nt_headers()->OptionalHeader.AddressOfEntryPoint;
|
||||
}
|
||||
|
||||
void* module::get_entry_point() const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
return this->get_ptr() + this->get_relative_entry_point();
|
||||
}
|
||||
|
||||
bool module::is_valid() const
|
||||
{
|
||||
return this->module_ != nullptr && this->get_dos_header()->e_magic == IMAGE_DOS_SIGNATURE;
|
||||
}
|
||||
|
||||
std::string module::get_name() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
auto path = this->get_path();
|
||||
const auto pos = path.find_last_of("/\\");
|
||||
if (pos == std::string::npos) return path;
|
||||
|
||||
return path.substr(pos + 1);
|
||||
}
|
||||
|
||||
std::string module::get_path() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
char name[MAX_PATH] = {0};
|
||||
GetModuleFileNameA(this->module_, name, sizeof name);
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string module::get_folder() const
|
||||
{
|
||||
if (!this->is_valid()) return "";
|
||||
|
||||
const auto path = std::filesystem::path(this->get_path());
|
||||
return path.parent_path().generic_string();
|
||||
}
|
||||
|
||||
void module::free()
|
||||
{
|
||||
if (this->is_valid())
|
||||
{
|
||||
FreeLibrary(this->module_);
|
||||
this->module_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
HMODULE module::get_handle() const
|
||||
{
|
||||
return this->module_;
|
||||
}
|
||||
|
||||
void** module::get_iat_entry(const std::string& module_name, const std::string& proc_name) const
|
||||
{
|
||||
if (!this->is_valid()) return nullptr;
|
||||
|
||||
const module other_module(module_name);
|
||||
if (!other_module.is_valid()) return nullptr;
|
||||
|
||||
const auto target_function = other_module.get_proc<void*>(proc_name);
|
||||
if (!target_function) return nullptr;
|
||||
|
||||
auto* header = this->get_optional_header();
|
||||
if (!header) return nullptr;
|
||||
|
||||
auto* import_descriptor = reinterpret_cast<PIMAGE_IMPORT_DESCRIPTOR>(this->get_ptr() + header->DataDirectory
|
||||
[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
|
||||
while (import_descriptor->Name)
|
||||
{
|
||||
if (!_stricmp(reinterpret_cast<char*>(this->get_ptr() + import_descriptor->Name), module_name.data()))
|
||||
{
|
||||
auto* original_thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->
|
||||
OriginalFirstThunk + this->get_ptr());
|
||||
auto* thunk_data = reinterpret_cast<PIMAGE_THUNK_DATA>(import_descriptor->FirstThunk + this->
|
||||
get_ptr());
|
||||
|
||||
while (original_thunk_data->u1.AddressOfData)
|
||||
{
|
||||
const size_t ordinal_number = original_thunk_data->u1.AddressOfData & 0xFFFFFFF;
|
||||
|
||||
if (ordinal_number > 0xFFFF) continue;
|
||||
|
||||
if (GetProcAddress(other_module.module_, reinterpret_cast<char*>(ordinal_number)) ==
|
||||
target_function)
|
||||
{
|
||||
return reinterpret_cast<void**>(&thunk_data->u1.Function);
|
||||
}
|
||||
|
||||
++original_thunk_data;
|
||||
++thunk_data;
|
||||
}
|
||||
|
||||
//break;
|
||||
}
|
||||
|
||||
++import_descriptor;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void raise_hard_exception()
|
||||
{
|
||||
int data = false;
|
||||
const module ntdll("ntdll.dll");
|
||||
ntdll.invoke_pascal<void>("RtlAdjustPrivilege", 19, true, false, &data);
|
||||
ntdll.invoke_pascal<void>("NtRaiseHardError", 0xC000007B, 0, nullptr, nullptr, 6, &data);
|
||||
}
|
||||
}
|
90
src/utils/nt.hpp
Normal file
90
src/utils/nt.hpp
Normal file
@ -0,0 +1,90 @@
|
||||
#pragma once
|
||||
|
||||
namespace utils::nt
|
||||
{
|
||||
class module final
|
||||
{
|
||||
public:
|
||||
static module load(const std::string& name);
|
||||
static module load(const std::filesystem::path& path);
|
||||
static module get_by_address(void* address);
|
||||
|
||||
module();
|
||||
explicit module(const std::string& name);
|
||||
explicit module(HMODULE handle);
|
||||
|
||||
module(const module& a) : module_(a.module_)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator!=(const module& obj) const { return !(*this == obj); };
|
||||
bool operator==(const module& obj) const;
|
||||
|
||||
operator bool() const;
|
||||
operator HMODULE() const;
|
||||
|
||||
void unprotect() const;
|
||||
void* get_entry_point() const;
|
||||
size_t get_relative_entry_point() const;
|
||||
|
||||
bool is_valid() const;
|
||||
std::string get_name() const;
|
||||
std::string get_path() const;
|
||||
std::string get_folder() const;
|
||||
std::uint8_t* get_ptr() const;
|
||||
void free();
|
||||
|
||||
HMODULE get_handle() const;
|
||||
|
||||
template <typename T>
|
||||
T get_proc(const std::string& process) const
|
||||
{
|
||||
if (!this->is_valid()) T{};
|
||||
return reinterpret_cast<T>(GetProcAddress(this->module_, process.data()));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::function<T> get(const std::string& process) const
|
||||
{
|
||||
if (!this->is_valid()) std::function<T>();
|
||||
return static_cast<T*>(this->get_proc<void*>(process));
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__cdecl)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke_pascal(const std::string& process, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__stdcall)(Args ...)>(process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
T invoke_this(const std::string& process, void* this_ptr, Args ... args) const
|
||||
{
|
||||
auto method = this->get<T(__thiscall)(void*, Args ...)>(this_ptr, process);
|
||||
if (method) return method(args...);
|
||||
return T();
|
||||
}
|
||||
|
||||
std::vector<PIMAGE_SECTION_HEADER> get_section_headers() const;
|
||||
|
||||
PIMAGE_NT_HEADERS get_nt_headers() const;
|
||||
PIMAGE_DOS_HEADER get_dos_header() const;
|
||||
PIMAGE_OPTIONAL_HEADER get_optional_header() const;
|
||||
|
||||
void** get_iat_entry(const std::string& module_name, const std::string& proc_name) const;
|
||||
|
||||
private:
|
||||
HMODULE module_;
|
||||
};
|
||||
|
||||
void raise_hard_exception();
|
||||
}
|
207
src/utils/signature.cpp
Normal file
207
src/utils/signature.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
#include <std_include.hpp>
|
||||
#include "signature.hpp"
|
||||
|
||||
namespace utils::hook
|
||||
{
|
||||
void signature::load_pattern(const std::string& pattern)
|
||||
{
|
||||
this->mask_.clear();
|
||||
this->pattern_.clear();
|
||||
|
||||
uint8_t nibble = 0;
|
||||
auto has_nibble = false;
|
||||
|
||||
for(auto val : pattern)
|
||||
{
|
||||
if (val == ' ') continue;
|
||||
if(val == '?')
|
||||
{
|
||||
this->mask_.push_back(val);
|
||||
this->pattern_.push_back(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if((val < '0' || val > '9') && (val < 'A' || val > 'F') && (val < 'a' || val> 'f'))
|
||||
{
|
||||
throw std::runtime_error("Invalid pattern");
|
||||
}
|
||||
|
||||
char str[] = { val, 0 };
|
||||
const auto current_nibble = static_cast<uint8_t>(strtol(str, nullptr, 16));
|
||||
|
||||
if(!has_nibble)
|
||||
{
|
||||
has_nibble = true;
|
||||
nibble = current_nibble;
|
||||
}
|
||||
else
|
||||
{
|
||||
has_nibble = false;
|
||||
const uint8_t byte = current_nibble | (nibble << 4);
|
||||
|
||||
this->mask_.push_back('x');
|
||||
this->pattern_.push_back(byte);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!this->mask_.empty() && this->mask_.back() == '?')
|
||||
{
|
||||
this->mask_.pop_back();
|
||||
this->pattern_.pop_back();
|
||||
}
|
||||
|
||||
if(this->has_sse_support())
|
||||
{
|
||||
while (this->pattern_.size() < 16)
|
||||
{
|
||||
this->pattern_.push_back(0);
|
||||
}
|
||||
}
|
||||
|
||||
if(has_nibble)
|
||||
{
|
||||
throw std::runtime_error("Invalid pattern");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<size_t> signature::process_range(uint8_t* start, const size_t length) const
|
||||
{
|
||||
if (this->has_sse_support()) return this->process_range_vectorized(start, length);
|
||||
return this->process_range_linear(start, length);
|
||||
}
|
||||
|
||||
std::vector<size_t> signature::process_range_linear(uint8_t* start, const size_t length) const
|
||||
{
|
||||
std::vector<size_t> result;
|
||||
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
{
|
||||
const auto address = start + i;
|
||||
|
||||
size_t j = 0;
|
||||
for (; j < this->mask_.size(); ++j)
|
||||
{
|
||||
if (this->mask_[j] != '?' && this->pattern_[j] != address[j])
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (j == this->mask_.size())
|
||||
{
|
||||
result.push_back(size_t(address));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<size_t> signature::process_range_vectorized(uint8_t* start, const size_t length) const
|
||||
{
|
||||
std::vector<size_t> result;
|
||||
__declspec(align(16)) char desired_mask[16] = { 0 };
|
||||
|
||||
for (size_t i = 0; i < this->mask_.size(); i++)
|
||||
{
|
||||
desired_mask[i / 8] |= (this->mask_[i] == '?' ? 0 : 1) << i % 8;
|
||||
}
|
||||
|
||||
const auto mask = _mm_load_si128(reinterpret_cast<const __m128i*>(desired_mask));
|
||||
const auto comparand = _mm_loadu_si128(reinterpret_cast<const __m128i*>(this->pattern_.data()));
|
||||
|
||||
for (size_t i = 0; i < length; ++i)
|
||||
{
|
||||
const auto address = start + i;
|
||||
const auto value = _mm_loadu_si128(reinterpret_cast<const __m128i*>(address));
|
||||
const auto comparison = _mm_cmpestrm(value, 16, comparand, static_cast<int>(this->mask_.size()), _SIDD_CMP_EQUAL_EACH);
|
||||
|
||||
const auto matches = _mm_and_si128(mask, comparison);
|
||||
const auto equivalence = _mm_xor_si128(mask, matches);
|
||||
|
||||
if (_mm_test_all_zeros(equivalence, equivalence))
|
||||
{
|
||||
result.push_back(size_t(address));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
signature::signature_result signature::process() const
|
||||
{
|
||||
const auto range = this->length_ - this->mask_.size();
|
||||
const auto cores = std::max(1u, std::thread::hardware_concurrency());
|
||||
|
||||
if (range <= cores * 10ull) return this->process_serial();
|
||||
return this->process_parallel();
|
||||
}
|
||||
|
||||
signature::signature_result signature::process_serial() const
|
||||
{
|
||||
const auto sub = this->has_sse_support() ? 16 : this->mask_.size();
|
||||
return { this->process_range(this->start_, this->length_ - sub) };
|
||||
}
|
||||
|
||||
signature::signature_result signature::process_parallel() const
|
||||
{
|
||||
const auto sub = this->has_sse_support() ? 16 : this->mask_.size();
|
||||
const auto range = this->length_ - sub;
|
||||
const auto cores = std::max(1u, std::thread::hardware_concurrency() / 2); // Only use half of the available cores
|
||||
const auto grid = range / cores;
|
||||
|
||||
std::mutex mutex;
|
||||
std::vector<size_t> result;
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for(auto i = 0u; i < cores; ++i)
|
||||
{
|
||||
const auto start = this->start_ + (grid * i);
|
||||
const auto length = (i + 1 == cores) ? (this->start_ + this->length_ - sub) - start : grid;
|
||||
threads.emplace_back([&, start, length]()
|
||||
{
|
||||
auto local_result = this->process_range(start, length);
|
||||
if (local_result.empty()) return;
|
||||
|
||||
std::lock_guard _(mutex);
|
||||
for(const auto& address : local_result)
|
||||
{
|
||||
result.push_back(address);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for(auto& t : threads)
|
||||
{
|
||||
if(t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(result.begin(), result.end());
|
||||
return { std::move(result) };
|
||||
}
|
||||
|
||||
bool signature::has_sse_support() const
|
||||
{
|
||||
if (this->mask_.size() <= 16)
|
||||
{
|
||||
int cpu_id[4];
|
||||
__cpuid(cpu_id, 0);
|
||||
|
||||
if (cpu_id[0] >= 1)
|
||||
{
|
||||
__cpuidex(cpu_id, 1, 0);
|
||||
return (cpu_id[2] & (1 << 20)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
utils::hook::signature::signature_result operator"" _sig(const char* str, const size_t len)
|
||||
{
|
||||
return utils::hook::signature(std::string(str, len)).process();
|
||||
}
|
73
src/utils/signature.hpp
Normal file
73
src/utils/signature.hpp
Normal file
@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
#include "nt.hpp"
|
||||
|
||||
namespace utils::hook
|
||||
{
|
||||
class signature final
|
||||
{
|
||||
public:
|
||||
class signature_result
|
||||
{
|
||||
public:
|
||||
signature_result(std::vector<size_t>&& matches) : matches_(std::move(matches))
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] uint8_t* get(const size_t index) const
|
||||
{
|
||||
if(index >= this->count())
|
||||
{
|
||||
throw std::runtime_error("Invalid index");
|
||||
}
|
||||
|
||||
return reinterpret_cast<uint8_t*>(this->matches_[index]);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t count() const
|
||||
{
|
||||
return this->matches_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<size_t> matches_;
|
||||
};
|
||||
|
||||
explicit signature(const std::string& pattern, const nt::module module = {})
|
||||
: signature(pattern, module.get_ptr(), module.get_optional_header()->SizeOfImage)
|
||||
{
|
||||
}
|
||||
|
||||
signature(const std::string& pattern, void* start, void* end)
|
||||
: signature(pattern, start, size_t(end) - size_t(start))
|
||||
{
|
||||
}
|
||||
|
||||
signature(const std::string& pattern, void* start, const size_t length)
|
||||
: start_(static_cast<uint8_t*>(start)), length_(length)
|
||||
{
|
||||
this->load_pattern(pattern);
|
||||
}
|
||||
|
||||
signature_result process() const;
|
||||
|
||||
private:
|
||||
std::string mask_;
|
||||
std::basic_string<uint8_t> pattern_;
|
||||
|
||||
uint8_t* start_;
|
||||
size_t length_;
|
||||
|
||||
void load_pattern(const std::string& pattern);
|
||||
|
||||
signature_result process_parallel() const;
|
||||
signature_result process_serial() const;
|
||||
std::vector<size_t> process_range(uint8_t* start, size_t length) const;
|
||||
std::vector<size_t> process_range_linear(uint8_t* start, size_t length) const;
|
||||
std::vector<size_t> process_range_vectorized(uint8_t* start, size_t length) const;
|
||||
|
||||
bool has_sse_support() const;
|
||||
};
|
||||
}
|
||||
|
||||
utils::hook::signature::signature_result operator"" _sig(const char* str, size_t len);
|
55
src/utils/string.cpp
Normal file
55
src/utils/string.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include <std_include.hpp>
|
||||
#include "string.hpp"
|
||||
|
||||
namespace utils::string
|
||||
{
|
||||
const char* va(const char* fmt, ...)
|
||||
{
|
||||
static thread_local va_provider<8, 256> provider;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
|
||||
const char* result = provider.get(fmt, ap);
|
||||
|
||||
va_end(ap);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_lower(std::string text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||
{
|
||||
return CHAR(tolower(input));
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string to_upper(std::string text)
|
||||
{
|
||||
std::transform(text.begin(), text.end(), text.begin(), [](const char input)
|
||||
{
|
||||
return CHAR(toupper(input));
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
std::string dump_hex(const std::string& data, const std::string& separator)
|
||||
{
|
||||
std::string result;
|
||||
|
||||
for (unsigned int i = 0; i < data.size(); ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
result.append(separator);
|
||||
}
|
||||
|
||||
result.append(va("%02X", data[i] & 0xFF));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
81
src/utils/string.hpp
Normal file
81
src/utils/string.hpp
Normal file
@ -0,0 +1,81 @@
|
||||
#pragma once
|
||||
#include "memory.hpp"
|
||||
|
||||
namespace utils::string
|
||||
{
|
||||
template <size_t Buffers, size_t MinBufferSize>
|
||||
class va_provider final
|
||||
{
|
||||
public:
|
||||
static_assert(Buffers != 0 && MinBufferSize != 0, "Buffers and MinBufferSize mustn't be 0");
|
||||
|
||||
va_provider() : current_buffer_(0)
|
||||
{
|
||||
}
|
||||
|
||||
char* get(const char* format, const va_list ap)
|
||||
{
|
||||
++this->current_buffer_ %= ARRAYSIZE(this->string_pool_);
|
||||
auto entry = &this->string_pool_[this->current_buffer_];
|
||||
|
||||
if (!entry->size || !entry->buffer)
|
||||
{
|
||||
throw std::runtime_error("String pool not initialized");
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
const int res = vsnprintf_s(entry->buffer, entry->size, _TRUNCATE, format, ap);
|
||||
if (res > 0) break; // Success
|
||||
if (res == 0) return nullptr; // Error
|
||||
|
||||
entry->double_size();
|
||||
}
|
||||
|
||||
return entry->buffer;
|
||||
}
|
||||
|
||||
private:
|
||||
class entry final
|
||||
{
|
||||
public:
|
||||
explicit entry(const size_t _size = MinBufferSize) : size(_size), buffer(nullptr)
|
||||
{
|
||||
if (this->size < MinBufferSize) this->size = MinBufferSize;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
~entry()
|
||||
{
|
||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||
this->size = 0;
|
||||
this->buffer = nullptr;
|
||||
}
|
||||
|
||||
void allocate()
|
||||
{
|
||||
if (this->buffer) memory::get_allocator()->free(this->buffer);
|
||||
this->buffer = memory::get_allocator()->allocate_array<char>(this->size + 1);
|
||||
}
|
||||
|
||||
void double_size()
|
||||
{
|
||||
this->size *= 2;
|
||||
this->allocate();
|
||||
}
|
||||
|
||||
size_t size;
|
||||
char* buffer;
|
||||
};
|
||||
|
||||
size_t current_buffer_;
|
||||
entry string_pool_[Buffers];
|
||||
};
|
||||
|
||||
const char* va(const char* fmt, ...);
|
||||
|
||||
std::string to_lower(std::string text);
|
||||
std::string to_upper(std::string text);
|
||||
|
||||
std::string dump_hex(const std::string& data, const std::string& separator = " ");
|
||||
}
|
BIN
tools/protoc.exe
Normal file
BIN
tools/protoc.exe
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user