mirror of
https://github.com/PretendoNetwork/rce_patches.git
synced 2025-04-02 11:02:12 -04:00
Compare commits
19 commits
Author | SHA1 | Date | |
---|---|---|---|
|
6a3f25d424 | ||
|
60ea5ea395 | ||
|
9b71db4762 | ||
|
252d7a2008 | ||
|
7cdf700879 | ||
|
5e2cc66656 | ||
|
6eb8886c56 | ||
|
353876a193 | ||
|
efb3bea72f | ||
|
ab7b4d3a2d | ||
|
920a43623e | ||
|
cf9620d7d3 | ||
|
8743a2e061 | ||
|
9a6431c669 | ||
|
d6f2ec2852 | ||
|
513f168913 | ||
|
ae503e18e5 | ||
|
67de80eea0 | ||
|
4d7011e72d |
20 changed files with 1033 additions and 390 deletions
67
.clang-format
Normal file
67
.clang-format
Normal file
|
@ -0,0 +1,67 @@
|
||||||
|
# Generated from CLion C/C++ Code Style settings
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: Consecutive
|
||||||
|
AlignConsecutiveMacros: AcrossEmptyLinesAndComments
|
||||||
|
AlignOperands: Align
|
||||||
|
AllowAllArgumentsOnNextLine: false
|
||||||
|
AllowAllConstructorInitializersOnNextLine: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Always
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: All
|
||||||
|
AllowShortIfStatementsOnASingleLine: Always
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
BraceWrapping:
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: Never
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterUnion: false
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyRecord: true
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializers: BeforeColon
|
||||||
|
BreakInheritanceList: BeforeColon
|
||||||
|
ColumnLimit: 0
|
||||||
|
CompactNamespaces: false
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
IndentCaseLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentWidth: 4
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||||
|
MaxEmptyLinesToKeep: 2
|
||||||
|
NamespaceIndentation: All
|
||||||
|
ObjCSpaceAfterProperty: false
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SpaceAfterCStyleCast: true
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: true
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
36
.github/workflows/build.yml
vendored
Normal file
36
.github/workflows/build.yml
vendored
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
name: Format and build
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
clang-format:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: clang-format
|
||||||
|
run: |
|
||||||
|
docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source
|
||||||
|
check-build-with-logging:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: clang-format
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: build binary with logging
|
||||||
|
run: |
|
||||||
|
docker build . -t builder
|
||||||
|
docker run --rm -v ${PWD}:/project builder make DEBUG=VERBOSE
|
||||||
|
docker run --rm -v ${PWD}:/project builder make clean
|
||||||
|
docker run --rm -v ${PWD}:/project builder make DEBUG=1
|
||||||
|
build-binary:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
needs: clang-format
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: build binary
|
||||||
|
run: |
|
||||||
|
docker build . -t builder
|
||||||
|
docker run --rm -v ${PWD}:/project builder make
|
||||||
|
- uses: actions/upload-artifact@master
|
||||||
|
with:
|
||||||
|
name: binary
|
||||||
|
path: "*.wps"
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -2,3 +2,4 @@
|
||||||
build/
|
build/
|
||||||
*.elf
|
*.elf
|
||||||
*.wps
|
*.wps
|
||||||
|
.idea/
|
||||||
|
|
7
Dockerfile
Normal file
7
Dockerfile
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
FROM wiiuenv/devkitppc:20230621
|
||||||
|
|
||||||
|
COPY --from=wiiuenv/libkernel:20220904 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/libfunctionpatcher:20230108 /artifacts $DEVKITPRO
|
||||||
|
COPY --from=wiiuenv/wiiupluginsystem:20230225 /artifacts $DEVKITPRO
|
||||||
|
|
||||||
|
WORKDIR project
|
339
LICENSE
Normal file
339
LICENSE
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Lesser General Public License instead.) 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
|
||||||
|
this service 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 make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. 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.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
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
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the 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 a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE 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.
|
||||||
|
|
||||||
|
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
|
||||||
|
convey 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 2 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, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision 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, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This 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.
|
24
Makefile
24
Makefile
|
@ -2,6 +2,8 @@
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DISTRO ?= git
|
||||||
|
|
||||||
ifeq ($(strip $(DEVKITPRO)),)
|
ifeq ($(strip $(DEVKITPRO)),)
|
||||||
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=<path to>/devkitpro")
|
||||||
endif
|
endif
|
||||||
|
@ -19,9 +21,9 @@ WUMS_ROOT := $(DEVKITPRO)/wums
|
||||||
# DATA is a list of directories containing data files
|
# DATA is a list of directories containing data files
|
||||||
# INCLUDES is a list of directories containing header files
|
# INCLUDES is a list of directories containing header files
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
TARGET := $(notdir $(CURDIR))
|
TARGET := rce_patches
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source source/patcher
|
SOURCES := source source/utils
|
||||||
DATA := data
|
DATA := data
|
||||||
INCLUDES := source
|
INCLUDES := source
|
||||||
|
|
||||||
|
@ -31,12 +33,22 @@ INCLUDES := source
|
||||||
CFLAGS := -Wall -O2 -ffunction-sections \
|
CFLAGS := -Wall -O2 -ffunction-sections \
|
||||||
$(MACHDEP)
|
$(MACHDEP)
|
||||||
|
|
||||||
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
|
CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__ -DDISTRO=\"$(DISTRO)\"
|
||||||
|
|
||||||
CXXFLAGS := $(CFLAGS) -std=gnu++20
|
CXXFLAGS := $(CFLAGS) -std=c++20
|
||||||
|
|
||||||
ASFLAGS := $(ARCH)
|
ASFLAGS := $(ARCH)
|
||||||
LDFLAGS = $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libfunctionpatcher.ld -T$(WUMS_ROOT)/share/libkernel.ld $(WUPSSPECS)
|
LDFLAGS = $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) $(WUPSSPECS)
|
||||||
|
|
||||||
|
ifeq ($(DEBUG),1)
|
||||||
|
CXXFLAGS += -DDEBUG -g
|
||||||
|
CFLAGS += -DDEBUG -g
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(DEBUG),VERBOSE)
|
||||||
|
CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||||
|
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||||
|
endif
|
||||||
|
|
||||||
LIBS := -lfunctionpatcher -lkernel -lwups -lwut
|
LIBS := -lfunctionpatcher -lkernel -lwups -lwut
|
||||||
|
|
||||||
|
@ -97,7 +109,7 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
|
||||||
all: $(BUILD)
|
all: $(BUILD)
|
||||||
|
|
||||||
$(BUILD):
|
$(BUILD):
|
||||||
@[ -d $@ ] || mkdir -p $@
|
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
|
||||||
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
|
|
67
README.md
67
README.md
|
@ -1,8 +1,59 @@
|
||||||
# Aroma plugin that fixes the RCE bugs on WiiU games
|
# rce_patches
|
||||||
|
This Aroma plugin provides fixes for games that have security and crashing issues that can be triggered in a multiplayer
|
||||||
- Mario Kart 8 (All regions, v64)
|
game. These patches are known to work on Nintendo Network as well as [Pretendo Network](https://pretendo.network).
|
||||||
- [ENLBufferPwn](https://github.com/PabloMK7/ENLBufferPwn) fix
|
Anyone playing multiplayer in affected games should have these patches installed.
|
||||||
- Identification token parsing RCE fix (exploit found by Kinnay)
|
|
||||||
|
The following fixes are provided:
|
||||||
- Splatoon (All regions, v272)
|
- Mario Kart 8 (All regions, v64)
|
||||||
- [ENLBufferPwn](https://github.com/PabloMK7/ENLBufferPwn) fix
|
- [ENLBufferPwn](https://github.com/PabloMK7/ENLBufferPwn) fix
|
||||||
|
- Identification token parsing RCE fix (exploit found by Kinnay)
|
||||||
|
- ENL nullptr deref fix + OOB read
|
||||||
|
|
||||||
|
- Splatoon (All regions, v272)
|
||||||
|
- [ENLBufferPwn](https://github.com/PabloMK7/ENLBufferPwn) fix
|
||||||
|
- ENL nullptr deref fix + OOB read
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Go to the [latest release](https://github.com/PretendoNetwork/rce_patches/releases/latest) and download the `.wps` file.
|
||||||
|
On your Wii U's SD card, place that file in `wiiu/environments/aroma/plugins`. Then reboot your console.
|
||||||
|
|
||||||
|
You can press L+Down+Minus on Aroma to view a config menu - if the installation worked, you should see "rce_patches"
|
||||||
|
listed in that menu. You're now safe to play online.
|
||||||
|
|
||||||
|
If you need help with the installation, you can ask in the [Pretendo discord](https://invite.gg/pretendo),
|
||||||
|
[Nintendo Homebrew](https://discord.gg/C29hYvh), or advanced users in the
|
||||||
|
[Aroma discord](https://discord.com/invite/bZ2rep2).
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
### Build options
|
||||||
|
Building via `make` only logs errors (via OSReport). To enable logging via the [LoggingModule](https://github.com/wiiu-env/LoggingModule) set `DEBUG` to `1` or `VERBOSE`.
|
||||||
|
|
||||||
|
`make` Logs errors only (via OSReport).
|
||||||
|
`make DEBUG=1` Enables information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||||
|
`make DEBUG=VERBOSE` Enables verbose information and error logging via [LoggingModule](https://github.com/wiiu-env/LoggingModule).
|
||||||
|
|
||||||
|
If the [LoggingModule](https://github.com/wiiu-env/LoggingModule) is not present, it'll fallback to UDP (Port 4405) and [CafeOS](https://github.com/wiiu-env/USBSerialLoggingModule) logging.
|
||||||
|
|
||||||
|
### Building using Docker
|
||||||
|
|
||||||
|
It's possible to use a docker image for building. This way you don't need anything installed on your host system.
|
||||||
|
|
||||||
|
```
|
||||||
|
# Build docker image (only needed once)
|
||||||
|
docker build . -t rcepatches-builder
|
||||||
|
|
||||||
|
# make
|
||||||
|
docker run -it --rm -v ${PWD}:/project rcepatches-builder make
|
||||||
|
|
||||||
|
# make clean
|
||||||
|
docker run -it --rm -v ${PWD}:/project rcepatches-builder make clean
|
||||||
|
```
|
||||||
|
|
||||||
|
### Formatting code using Docker
|
||||||
|
|
||||||
|
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source -i`
|
||||||
|
|
||||||
|
## Licensing
|
||||||
|
To ensure everyone has access to every fix, these patches are under GPLv2. Unless you're a programmer at Nintendo, then
|
||||||
|
you can have the patches for free ;)
|
104
source/config.cpp
Normal file
104
source/config.cpp
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
#include "config.h"
|
||||||
|
#include "globals.h"
|
||||||
|
#include "patches.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <coreinit/title.h>
|
||||||
|
#include <string>
|
||||||
|
#include <sysapp/launch.h>
|
||||||
|
#include <wups.h>
|
||||||
|
#include <wups/config/WUPSConfigItemBoolean.h>
|
||||||
|
|
||||||
|
#define MK8PATCHES_CONFIG_ID "mk8patches"
|
||||||
|
#define SPLATOONPATCHES_CONFIG_ID "splatoonpatches"
|
||||||
|
|
||||||
|
#define LOAD_BOOL_FROM_CONFIG(config_name, __variable__) \
|
||||||
|
if ((storageRes = WUPS_GetBool(nullptr, config_name, &__variable__)) == WUPS_STORAGE_ERROR_NOT_FOUND) { \
|
||||||
|
if (WUPS_StoreBool(nullptr, config_name, __variable__) != WUPS_STORAGE_ERROR_SUCCESS) { \
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Failed to store bool"); \
|
||||||
|
} \
|
||||||
|
} else if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) { \
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("Failed to get bool %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes); \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
|
||||||
|
|
||||||
|
#define PROCESS_BOOL_ITEM_CHANGED(__config__name, __variable__) \
|
||||||
|
if (std::string_view(item->configId) == __config__name) { \
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("New value in %s: %d", __config__name, newValue); \
|
||||||
|
__variable__ = newValue; \
|
||||||
|
WUPS_StoreInt(nullptr, __config__name, __variable__); \
|
||||||
|
return; \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
|
||||||
|
bool prevActivateMK8Patches = true;
|
||||||
|
bool prevActivateSplatoonPatches = true;
|
||||||
|
|
||||||
|
void readStorage() {
|
||||||
|
// Open storage to read values
|
||||||
|
WUPSStorageError storageRes = WUPS_OpenStorage();
|
||||||
|
if (storageRes != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to open storage %s (%d)", WUPS_GetStorageStatusStr(storageRes), storageRes);
|
||||||
|
} else {
|
||||||
|
LOAD_BOOL_FROM_CONFIG(MK8PATCHES_CONFIG_ID, gActivateMK8Patches);
|
||||||
|
LOAD_BOOL_FROM_CONFIG(SPLATOONPATCHES_CONFIG_ID, gActivateSplatoonPatches);
|
||||||
|
|
||||||
|
prevActivateMK8Patches = gActivateMK8Patches;
|
||||||
|
prevActivateSplatoonPatches = gActivateSplatoonPatches;
|
||||||
|
|
||||||
|
// Close storage
|
||||||
|
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE("Failed to close storage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void boolItemChanged(ConfigItemBoolean *item, bool newValue) {
|
||||||
|
PROCESS_BOOL_ITEM_CHANGED(MK8PATCHES_CONFIG_ID, gActivateMK8Patches);
|
||||||
|
PROCESS_BOOL_ITEM_CHANGED(SPLATOONPATCHES_CONFIG_ID, gActivateSplatoonPatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_GET_CONFIG() {
|
||||||
|
// We open the storage, so we can persist the configuration the user did.
|
||||||
|
if (WUPS_OpenStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE("Failed to open storage");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPSConfigHandle config;
|
||||||
|
WUPSConfig_CreateHandled(&config, "RCE Patches");
|
||||||
|
|
||||||
|
WUPSConfigCategoryHandle cat;
|
||||||
|
WUPSConfig_AddCategoryByNameHandled(config, "Games", &cat);
|
||||||
|
|
||||||
|
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, MK8PATCHES_CONFIG_ID, "Patch exploits in Mario Kart 8", gActivateMK8Patches, &boolItemChanged);
|
||||||
|
WUPSConfigItemBoolean_AddToCategoryHandled(config, cat, SPLATOONPATCHES_CONFIG_ID, "Patch exploits in Splatoon", gActivateSplatoonPatches, &boolItemChanged);
|
||||||
|
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
WUPS_CONFIG_CLOSED() {
|
||||||
|
// Save all changes
|
||||||
|
if (WUPS_CloseStorage() != WUPS_STORAGE_ERROR_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE("Failed to close storage");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevActivateMK8Patches != gActivateMK8Patches) {
|
||||||
|
if (OSGetTitleID() == MARIO_KART_8_TID_J ||
|
||||||
|
OSGetTitleID() == MARIO_KART_8_TID_E ||
|
||||||
|
OSGetTitleID() == MARIO_KART_8_TID_U) {
|
||||||
|
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prevActivateSplatoonPatches != gActivateSplatoonPatches) {
|
||||||
|
if (OSGetTitleID() == SPLATOON_TID_J ||
|
||||||
|
OSGetTitleID() == SPLATOON_TID_E ||
|
||||||
|
OSGetTitleID() == SPLATOON_TID_U) {
|
||||||
|
_SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prevActivateMK8Patches = gActivateMK8Patches;
|
||||||
|
prevActivateSplatoonPatches = gActivateSplatoonPatches;
|
||||||
|
}
|
2
source/config.h
Normal file
2
source/config.h
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
void readStorage();
|
2
source/globals.cpp
Normal file
2
source/globals.cpp
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
bool gActivateMK8Patches = true;
|
||||||
|
bool gActivateSplatoonPatches = true;
|
4
source/globals.h
Normal file
4
source/globals.h
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern bool gActivateMK8Patches;
|
||||||
|
extern bool gActivateSplatoonPatches;
|
135
source/main.cpp
135
source/main.cpp
|
@ -1,64 +1,87 @@
|
||||||
#include <wups.h>
|
#include "config.h"
|
||||||
#include <string.h>
|
#include "globals.h"
|
||||||
|
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <cstring>
|
||||||
|
#include <function_patcher/function_patching.h>
|
||||||
|
#include <vector>
|
||||||
|
#include <wups.h>
|
||||||
|
|
||||||
WUPS_PLUGIN_NAME("rce_patches");
|
WUPS_PLUGIN_NAME("rce_patches");
|
||||||
WUPS_PLUGIN_DESCRIPTION("Patches security issues in WiiU games that could be triggered remotely");
|
WUPS_PLUGIN_DESCRIPTION("Patches security issues in WiiU games that could be triggered remotely");
|
||||||
WUPS_PLUGIN_VERSION("v1.0");
|
WUPS_PLUGIN_VERSION("v1.1-" DISTRO);
|
||||||
WUPS_PLUGIN_AUTHOR("Rambo6Glaz");
|
WUPS_PLUGIN_AUTHOR("Rambo6Glaz, Maschell");
|
||||||
WUPS_PLUGIN_LICENSE("");
|
WUPS_PLUGIN_LICENSE("");
|
||||||
|
WUPS_USE_STORAGE("rce_patches"); // Unique id for the storage api
|
||||||
|
|
||||||
std::optional<rplinfo> gRPLInfo;
|
std::vector<PatchData> mk8Patches;
|
||||||
|
std::vector<PatchData> splatoonPatches;
|
||||||
|
|
||||||
ON_APPLICATION_START()
|
void RemovePatches(std::vector<PatchData> &patchHandles) {
|
||||||
{
|
for (auto &patch : patchHandles) {
|
||||||
|
if (FunctionPatcher_RemoveFunctionPatch(patch.handle) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
// If this is not a supported title, no need to do anything
|
DEBUG_FUNCTION_LINE_WARN("Failed to remove function patch %08X", patch.handle);
|
||||||
uint64_t titleId = OSGetTitleID();
|
}
|
||||||
GamePatches *gamePatch = nullptr;
|
}
|
||||||
for (auto &patch : sGamePatchList)
|
patchHandles.clear();
|
||||||
{
|
|
||||||
for (int i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (patch.mRegionalTIDs[i] == titleId)
|
|
||||||
{
|
|
||||||
gamePatch = &patch;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!gamePatch)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Init logging
|
|
||||||
if (!WHBLogModuleInit())
|
|
||||||
{
|
|
||||||
WHBLogCafeInit();
|
|
||||||
WHBLogUdpInit();
|
|
||||||
}
|
|
||||||
|
|
||||||
WHBLogPrintf("rce_patches: applying patches for %s...", gamePatch->mTitleName);
|
|
||||||
|
|
||||||
// Patch the dynload functions so GetRPLInfo works
|
|
||||||
if (!PatchDynLoadFunctions())
|
|
||||||
{
|
|
||||||
WHBLogPrintf("rce_patches: Failed to patch dynload functions");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the RPLInfo
|
|
||||||
gRPLInfo = TryGetRPLInfo();
|
|
||||||
if (!gRPLInfo)
|
|
||||||
{
|
|
||||||
WHBLogPrintf("rce_patches: Failed to get RPL info");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For each patch type, call apply patch func (terrible design lol)
|
|
||||||
for (auto &patch : gamePatch->mPatchTypes)
|
|
||||||
{
|
|
||||||
gamePatch->mPatchFunc(patch);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INITIALIZE_PLUGIN() {
|
||||||
|
DEBUG_FUNCTION_LINE("Patch functions");
|
||||||
|
if (FunctionPatcher_InitLibrary() != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
|
OSFatal("rce_patches: FunctionPatcher_InitLibrary failed");
|
||||||
|
}
|
||||||
|
readStorage();
|
||||||
|
}
|
||||||
|
|
||||||
|
DEINITIALIZE_PLUGIN() {
|
||||||
|
RemovePatches(mk8Patches);
|
||||||
|
RemovePatches(splatoonPatches);
|
||||||
|
}
|
||||||
|
|
||||||
|
ON_APPLICATION_START() {
|
||||||
|
initLogging();
|
||||||
|
|
||||||
|
if (!gActivateMK8Patches && !mk8Patches.empty()) {
|
||||||
|
DEBUG_FUNCTION_LINE("Remove MK8 patches");
|
||||||
|
RemovePatches(mk8Patches);
|
||||||
|
} else if (gActivateMK8Patches && mk8Patches.empty()) {
|
||||||
|
DEBUG_FUNCTION_LINE("Add MK8 patches");
|
||||||
|
if (!MARIO_KART_8_AddPatches(mk8Patches)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add Mario Kart 8 patches");
|
||||||
|
RemovePatches(mk8Patches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!gActivateSplatoonPatches && !splatoonPatches.empty()) {
|
||||||
|
DEBUG_FUNCTION_LINE("Remove Splatoon patches");
|
||||||
|
RemovePatches(splatoonPatches);
|
||||||
|
} else if (gActivateSplatoonPatches && splatoonPatches.empty()) {
|
||||||
|
DEBUG_FUNCTION_LINE("Add Splatoon patches");
|
||||||
|
if (!SPLATOON_AddPatches(splatoonPatches)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add Splatoon patches");
|
||||||
|
RemovePatches(splatoonPatches);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &patch : mk8Patches) {
|
||||||
|
bool isPatched = false;
|
||||||
|
if (FunctionPatcher_IsFunctionPatched(patch.handle, &isPatched) == FUNCTION_PATCHER_RESULT_SUCCESS && isPatched) {
|
||||||
|
DEBUG_FUNCTION_LINE("MK8: Function %s (handle: %08X) has been patched", patch.name.c_str(), patch.handle);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("MK8: Function %s (handle: %08X) has NOT been patched", patch.name.c_str(), patch.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto &patch : splatoonPatches) {
|
||||||
|
bool isPatched = false;
|
||||||
|
if (FunctionPatcher_IsFunctionPatched(patch.handle, &isPatched) == FUNCTION_PATCHER_RESULT_SUCCESS && isPatched) {
|
||||||
|
DEBUG_FUNCTION_LINE("Splatoon: Function %s (handle: %08X) has been patched", patch.name.c_str(), patch.handle);
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Splatoon: Function %s (handle: %08X) has NOT been patched", patch.name.c_str(), patch.handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ON_APPLICATION_ENDS() {
|
||||||
|
deinitLogging();
|
||||||
|
}
|
|
@ -1,20 +0,0 @@
|
||||||
#include "patcher.h"
|
|
||||||
|
|
||||||
#include "utils/logger.h"
|
|
||||||
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
#include <coreinit/memorymap.h>
|
|
||||||
|
|
||||||
bool replace_string(uint32_t start, uint32_t size, const char* original_val, size_t original_val_sz, const char* new_val, size_t new_val_sz) {
|
|
||||||
for (uint32_t addr = start; addr < start + size - original_val_sz; addr++) {
|
|
||||||
int ret = memcmp(original_val, (void*)addr, original_val_sz);
|
|
||||||
if (ret == 0) {
|
|
||||||
DEBUG_FUNCTION_LINE("found str @%08x: %s", addr, (const char*)addr);
|
|
||||||
KernelCopyData(OSEffectiveToPhysical(addr), OSEffectiveToPhysical((uint32_t)new_val), new_val_sz);
|
|
||||||
DEBUG_FUNCTION_LINE("new str @%08x: %s", addr, (const char*)addr);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
bool replace_string(uint32_t start, uint32_t size, const char* original_val, size_t original_val_sz, const char* new_val, size_t new_val_sz);
|
|
|
@ -1,78 +0,0 @@
|
||||||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
|
||||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
|
||||||
granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
||||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "rplinfo.h"
|
|
||||||
|
|
||||||
#include "utils/logger.h"
|
|
||||||
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
|
|
||||||
#include <coreinit/cache.h>
|
|
||||||
#include <coreinit/memorymap.h>
|
|
||||||
|
|
||||||
std::optional<std::vector<OSDynLoad_NotifyData>> TryGetRPLInfo()
|
|
||||||
{
|
|
||||||
int num_rpls = OSDynLoad_GetNumberOfRPLs();
|
|
||||||
if (num_rpls == 0)
|
|
||||||
{
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_FUNCTION_LINE("num_rpls: %d", num_rpls);
|
|
||||||
|
|
||||||
std::vector<OSDynLoad_NotifyData> rpls;
|
|
||||||
rpls.resize(num_rpls);
|
|
||||||
|
|
||||||
bool ret = OSDynLoad_GetRPLInfo(0, num_rpls, rpls.data());
|
|
||||||
if (!ret)
|
|
||||||
{
|
|
||||||
return std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rpls;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PatchInstruction(void *instr, uint32_t original, uint32_t replacement)
|
|
||||||
{
|
|
||||||
uint32_t current = *(uint32_t *)instr;
|
|
||||||
DEBUG_FUNCTION_LINE("current instr %08x", current);
|
|
||||||
if (current != original)
|
|
||||||
return current == replacement;
|
|
||||||
|
|
||||||
KernelCopyData(OSEffectiveToPhysical((uint32_t)instr), OSEffectiveToPhysical((uint32_t)&replacement), sizeof(replacement));
|
|
||||||
// Only works on AROMA! WUPS 0.1's KernelCopyData is uncached, needs DCInvalidate here instead
|
|
||||||
DCFlushRange(instr, 4);
|
|
||||||
ICInvalidateRange(instr, 4);
|
|
||||||
|
|
||||||
current = *(uint32_t *)instr;
|
|
||||||
DEBUG_FUNCTION_LINE("patched instr %08x", current);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool PatchDynLoadFunctions()
|
|
||||||
{
|
|
||||||
uint32_t *patch1 = ((uint32_t *)&OSDynLoad_GetNumberOfRPLs) + 6;
|
|
||||||
uint32_t *patch2 = ((uint32_t *)&OSDynLoad_GetRPLInfo) + 22;
|
|
||||||
|
|
||||||
if (!PatchInstruction(patch1, 0x41820038 /* beq +38 */, 0x60000000 /*nop*/))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (!PatchInstruction(patch2, 0x41820100 /* beq +100 */, 0x60000000 /*nop*/))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
/* Copyright 2022 Pretendo Network contributors <pretendo.network>
|
|
||||||
Copyright 2022 Ash Logan <ash@heyquark.com>
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby
|
|
||||||
granted, provided that the above copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
||||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
||||||
PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
*/
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include <coreinit/dynload.h>
|
|
||||||
|
|
||||||
using rplinfo = std::vector<OSDynLoad_NotifyData>;
|
|
||||||
|
|
||||||
std::optional<rplinfo> TryGetRPLInfo();
|
|
||||||
bool PatchDynLoadFunctions();
|
|
||||||
|
|
||||||
constexpr inline std::optional<OSDynLoad_NotifyData> FindRPL(const rplinfo &rpls, const std::string &name)
|
|
||||||
{
|
|
||||||
auto res = std::find_if(rpls.cbegin(), rpls.cend(), [&](const OSDynLoad_NotifyData &data)
|
|
||||||
{ return std::string(data.name).ends_with(name); });
|
|
||||||
if (res == rpls.cend())
|
|
||||||
return std::nullopt;
|
|
||||||
return *res;
|
|
||||||
}
|
|
|
@ -1,115 +1,169 @@
|
||||||
#include "patches.h"
|
#include "patches.h"
|
||||||
|
#include "utils/logger.h"
|
||||||
|
#include <function_patcher/function_patching.h>
|
||||||
|
#include <set>
|
||||||
|
|
||||||
// ==========================================================================================
|
// ==========================================================================================
|
||||||
|
DECL_FUNCTION(bool, enl_ParseIdentificationToken, void *identifiationInfo, sead_String *identificationToken) {
|
||||||
|
// Fix for RCE (stack overflow if identification buffer was bigger than 16)
|
||||||
|
if (strnlen(identificationToken->mBuffer, 16) == 16) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("Avoided bufferoverlow in enl_ParseIdentificationToken!");
|
||||||
|
identificationToken->mBuffer[15] = '\0';
|
||||||
|
return real_enl_ParseIdentificationToken(identifiationInfo, identificationToken);
|
||||||
|
}
|
||||||
|
|
||||||
DECL_FUNCTION(bool, enl_ParseIdentificationToken, void *identifiationInfo, sead_String *identificationToken)
|
return real_enl_ParseIdentificationToken(identifiationInfo, identificationToken);
|
||||||
{
|
|
||||||
|
|
||||||
// Fix for RCE (stack overflow if identification buffer was bigger than 16)
|
|
||||||
if (strnlen(identificationToken->mBuffer, 16) == 16)
|
|
||||||
{
|
|
||||||
identificationToken->mBuffer[15] = '\0';
|
|
||||||
return real_enl_ParseIdentificationToken(identifiationInfo, identificationToken);
|
|
||||||
}
|
|
||||||
|
|
||||||
return real_enl_ParseIdentificationToken(identifiationInfo, identificationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enl_ContentTransporter *(*real_enl_TransportManager_getContentTransporter)(void *_this, unsigned char &id);
|
DECL_FUNCTION(enl_ContentTransporter *, enl_TransportManager_getContentTransporter, void *_this, unsigned char &id) {
|
||||||
DECL_FUNCTION(void, enl_TransportManager_updateReceiveBuffer_, void *_this, signed char const &bufferId, uint8_t *data, uint32_t size)
|
return real_enl_TransportManager_getContentTransporter(_this, id);
|
||||||
{
|
}
|
||||||
|
|
||||||
// Loop through all records and check if there's a bad record (size mismatch) until out of bounds or end record
|
DECL_FUNCTION(void, enl_TransportManager_updateReceiveBuffer_, void *_this, signed char const &bufferId, uint8_t *data, uint32_t size) {
|
||||||
uint8_t *pData = data;
|
|
||||||
while (pData < (data + size))
|
|
||||||
{
|
|
||||||
enl_RecordHeader *record = (enl_RecordHeader *)pData;
|
|
||||||
if (record->mContentLength == 0 && record->mContentTransporterID == 0xff)
|
|
||||||
break;
|
|
||||||
|
|
||||||
enl_ContentTransporter *contentTransp = real_enl_TransportManager_getContentTransporter(_this, record->mContentTransporterID);
|
static enl_RecordHeader s_TerminationRecord = {.mContentTransporterID = 0xff, .mContentLength = 0};
|
||||||
// Actual fix for the ENL nullptr deref crash (lmao)
|
|
||||||
if (!contentTransp)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Fix for RCE (if size mismatch, do not handle packet.)
|
// Check for end record in the data, if there is not, drop packet
|
||||||
if (contentTransp->vtable->getSendBufferSize(contentTransp) != record->mContentLength)
|
bool hasEndRecord = false;
|
||||||
return;
|
|
||||||
|
|
||||||
pData += sizeof(enl_RecordHeader);
|
// Loop through all records and check if there's a bad record (size mismatch) until out of bounds or end record
|
||||||
pData += record->mContentLength;
|
uint8_t *pData = data;
|
||||||
}
|
while (pData < (data + size)) {
|
||||||
|
enl_RecordHeader *record = (enl_RecordHeader *) pData;
|
||||||
|
if (record->mContentLength == 0 && record->mContentTransporterID == 0xff) {
|
||||||
|
hasEndRecord = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return real_enl_TransportManager_updateReceiveBuffer_(_this, bufferId, data, size);
|
enl_ContentTransporter *contentTransp = real_enl_TransportManager_getContentTransporter(_this, record->mContentTransporterID);
|
||||||
|
// Actual fix for the ENL nullptr deref crash (lmao)
|
||||||
|
if (!contentTransp) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("Avoided ENL nullptr deref crash in enl_TransportManager_updateReceiveBuffer_!");
|
||||||
|
return real_enl_TransportManager_updateReceiveBuffer_(_this, bufferId, (uint8_t *) &s_TerminationRecord, sizeof(enl_RecordHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (record->mContentLength > 0x440) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("record->mContentLength was over 0x440 in enl_TransportManager_updateReceiveBuffer_!");
|
||||||
|
return real_enl_TransportManager_updateReceiveBuffer_(_this, bufferId, (uint8_t *) &s_TerminationRecord, sizeof(enl_RecordHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
pData += sizeof(enl_RecordHeader);
|
||||||
|
pData += record->mContentLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasEndRecord) {
|
||||||
|
return real_enl_TransportManager_updateReceiveBuffer_(_this, bufferId, (uint8_t *) &s_TerminationRecord, sizeof(enl_RecordHeader));
|
||||||
|
}
|
||||||
|
|
||||||
|
return real_enl_TransportManager_updateReceiveBuffer_(_this, bufferId, data, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
DECL_FUNCTION(void, enl_Buffer_set, enl_Buffer *_this, uint8_t const *data, size_t size) {
|
||||||
|
// Fix for the RCE
|
||||||
|
if (!_this->mData || !size || size > _this->mCapacity) {
|
||||||
|
DEBUG_FUNCTION_LINE_INFO("Avoided overflow in enl_Buffer_set!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(_this->mData, data, size);
|
||||||
|
_this->mSize = size;
|
||||||
|
}
|
||||||
|
// ==========================================================================================
|
||||||
|
|
||||||
|
bool MARIO_KART_8_AddPatches(std::vector<PatchData> &functionPatches) {
|
||||||
|
uint64_t titleIds[] = {MARIO_KART_8_TID};
|
||||||
|
function_replacement_data_t repl = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||||
|
enl_ParseIdentificationToken,
|
||||||
|
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||||
|
"Turbo.rpx",
|
||||||
|
0x8E3930, // Address of 'enl::PiaUtil::ParseIdentificationToken'
|
||||||
|
64, 64);
|
||||||
|
PatchedFunctionHandle handle = 0;
|
||||||
|
if (FunctionPatcher_AddFunctionPatch(&repl, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add \"enl_ParseIdentificationToken\" patch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
functionPatches.emplace_back("enl::PiaUtil::ParseIdentificationToken", handle);
|
||||||
|
|
||||||
|
function_replacement_data_t repl1 = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||||
|
enl_TransportManager_getContentTransporter,
|
||||||
|
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||||
|
"Turbo.rpx",
|
||||||
|
0x8D7678, // Address of 'enl::TransportManager::getContentTransporter'
|
||||||
|
64, 64);
|
||||||
|
if (FunctionPatcher_AddFunctionPatch(&repl1, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add \"enl_TransportManager_getContentTransporter\" patch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
functionPatches.emplace_back("enl::TransportManager::getContentTransporter", handle);
|
||||||
|
|
||||||
|
|
||||||
|
function_replacement_data_t repl2 = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||||
|
enl_TransportManager_updateReceiveBuffer_,
|
||||||
|
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||||
|
"Turbo.rpx",
|
||||||
|
0x8D772C, // Address of 'enl::TransportManager::updateReceiveBuffer_'
|
||||||
|
64, 64);
|
||||||
|
if (FunctionPatcher_AddFunctionPatch(&repl2, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add \"enl_TransportManager_updateReceiveBuffer_\" patch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
functionPatches.emplace_back("enl::TransportManager::updateReceiveBuffer_", handle);
|
||||||
|
|
||||||
|
function_replacement_data_t repl3 = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||||
|
enl_Buffer_set,
|
||||||
|
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||||
|
"Turbo.rpx",
|
||||||
|
0x8CF228,
|
||||||
|
64, 64);
|
||||||
|
if (FunctionPatcher_AddFunctionPatch(&repl3, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add \"enl_Buffer_set\" patch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
functionPatches.emplace_back("enl:Buffer::set", handle);
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================================================================
|
// ==========================================================================================
|
||||||
|
|
||||||
void MARIO_KART_8_ApplyPatch(EPatchType type)
|
bool SPLATOON_AddPatches(std::vector<PatchData> &functionPatches) {
|
||||||
{
|
uint64_t titleIds[] = {SPLATOON_TID};
|
||||||
auto turbo_rpx = FindRPL(*gRPLInfo, "Turbo.rpx");
|
function_replacement_data_t repl = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||||
if (!turbo_rpx)
|
enl_TransportManager_getContentTransporter,
|
||||||
{
|
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||||
WHBLogPrintf("rce_patches: Couldn't find Turbo.rpx ...");
|
"Gambit.rpx",
|
||||||
return;
|
0xB4108C, // Address of 'enl::TransportManager::getContentTransporter'
|
||||||
}
|
272, 272);
|
||||||
|
PatchedFunctionHandle handle;
|
||||||
|
if (FunctionPatcher_AddFunctionPatch(&repl, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to add \"enl_TransportManager_getContentTransporter\" patch");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
functionPatches.emplace_back("enl::TransportManager::getContentTransporter", handle);
|
||||||
|
|
||||||
if (type == PATCH_ENL_ID_TOKEN_RCE)
|
function_replacement_data_t repl1 = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||||
{
|
enl_TransportManager_updateReceiveBuffer_,
|
||||||
// Address of 'enl::PiaUtil::ParseIdentificationToken'
|
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||||
uint32_t addr_func = turbo_rpx->textAddr + 0x8E3930;
|
"Gambit.rpx",
|
||||||
function_replacement_data_t repl = REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(
|
0xB41140, // Address of 'enl::TransportManager::updateReceiveBuffer_'
|
||||||
enl_ParseIdentificationToken,
|
272, 272);
|
||||||
OSEffectiveToPhysical(addr_func),
|
if (FunctionPatcher_AddFunctionPatch(&repl1, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
addr_func,
|
DEBUG_FUNCTION_LINE_ERR("Failed to add \"enl_TransportManager_updateReceiveBuffer_\" patch");
|
||||||
FP_TARGET_PROCESS_GAME_AND_MENU);
|
return false;
|
||||||
FunctionPatcherPatchFunction(&repl, nullptr);
|
}
|
||||||
|
functionPatches.emplace_back("enl::TransportManager::updateReceiveBuffer_", handle);
|
||||||
|
|
||||||
WHBLogPrintf("rce_patches: Patched Mario Kart 8 (PATCH_ENL_ID_TOKEN_RCE)");
|
function_replacement_data_t repl2 = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||||
}
|
enl_Buffer_set,
|
||||||
|
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||||
if (type == PATCH_ENL_BUFFER_RCE)
|
"Gambit.rpx",
|
||||||
{
|
0xB4D178, // Address of 'enl:Buffer::set'
|
||||||
real_enl_TransportManager_getContentTransporter = (enl_ContentTransporter * (*)(void *, unsigned char &))(turbo_rpx->textAddr + 0x8D7678);
|
272, 272);
|
||||||
|
if (FunctionPatcher_AddFunctionPatch(&repl2, &handle, nullptr) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||||
// Address of 'enl::TransportManager::updateReceiveBuffer_'
|
DEBUG_FUNCTION_LINE_ERR("Failed to add \"enl_Buffer_set\" patch");
|
||||||
uint32_t addr_func = turbo_rpx->textAddr + 0x8D772C;
|
return false;
|
||||||
function_replacement_data_t repl = REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(
|
}
|
||||||
enl_TransportManager_updateReceiveBuffer_,
|
functionPatches.emplace_back("enl:Buffer::set", handle);
|
||||||
OSEffectiveToPhysical(addr_func),
|
return true;
|
||||||
addr_func,
|
|
||||||
FP_TARGET_PROCESS_GAME_AND_MENU);
|
|
||||||
FunctionPatcherPatchFunction(&repl, nullptr);
|
|
||||||
|
|
||||||
WHBLogPrintf("rce_patches: Patched Mario Kart 8 (PATCH_ENL_BUFFER_RCE)");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==========================================================================================
|
|
||||||
|
|
||||||
void SPLATOON_ApplyPatch(EPatchType type)
|
|
||||||
{
|
|
||||||
|
|
||||||
auto gambit_rpx = FindRPL(*gRPLInfo, "Gambit.rpx");
|
|
||||||
if (!gambit_rpx)
|
|
||||||
{
|
|
||||||
WHBLogPrintf("rce_patches: Couldn't find Gambit.rpx ...");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type == PATCH_ENL_BUFFER_RCE)
|
|
||||||
{
|
|
||||||
real_enl_TransportManager_getContentTransporter = (enl_ContentTransporter * (*)(void *, unsigned char &))(gambit_rpx->textAddr + 0xB4108C);
|
|
||||||
|
|
||||||
// Address of 'enl::TransportManager::updateReceiveBuffer_'
|
|
||||||
uint32_t addr_func = gambit_rpx->textAddr + 0xB41140;
|
|
||||||
function_replacement_data_t repl = REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(
|
|
||||||
enl_TransportManager_updateReceiveBuffer_,
|
|
||||||
OSEffectiveToPhysical(addr_func),
|
|
||||||
addr_func,
|
|
||||||
FP_TARGET_PROCESS_GAME_AND_MENU);
|
|
||||||
FunctionPatcherPatchFunction(&repl, nullptr);
|
|
||||||
|
|
||||||
WHBLogPrintf("rce_patches: Patched Splatoon (PATCH_ENL_BUFFER_RCE)");
|
|
||||||
}
|
|
||||||
}
|
|
143
source/patches.h
143
source/patches.h
|
@ -1,72 +1,82 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <vector>
|
|
||||||
#include <cstring>
|
|
||||||
|
|
||||||
#include <whb/log.h>
|
|
||||||
#include <whb/log_module.h>
|
|
||||||
#include <whb/log_cafe.h>
|
|
||||||
#include <whb/log_udp.h>
|
|
||||||
|
|
||||||
#include <coreinit/title.h>
|
|
||||||
|
|
||||||
#include <patcher/rplinfo.h>
|
|
||||||
#include <patcher/patcher.h>
|
|
||||||
|
|
||||||
#include <kernel/kernel.h>
|
|
||||||
|
|
||||||
#include <coreinit/cache.h>
|
#include <coreinit/cache.h>
|
||||||
#include <coreinit/memorymap.h>
|
#include <coreinit/memorymap.h>
|
||||||
|
#include <coreinit/title.h>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <function_patcher/fpatching_defines.h>
|
||||||
|
#include <kernel/kernel.h>
|
||||||
|
#include <set>
|
||||||
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#undef DECL_FUNCTION
|
struct sead_String {
|
||||||
#include <function_patcher/function_patching.h>
|
char *mBuffer;
|
||||||
|
uint32_t vtable;
|
||||||
enum EPatchType
|
|
||||||
{
|
|
||||||
PATCH_ENL_BUFFER_RCE,
|
|
||||||
PATCH_ENL_ID_TOKEN_RCE,
|
|
||||||
};
|
};
|
||||||
|
WUT_CHECK_OFFSET(sead_String, 0x00, mBuffer);
|
||||||
|
WUT_CHECK_OFFSET(sead_String, 0x04, vtable);
|
||||||
|
|
||||||
struct GamePatches
|
struct __attribute__((__packed__)) enl_RecordHeader {
|
||||||
{
|
uint8_t mContentTransporterID;
|
||||||
const char *mTitleName;
|
uint16_t mContentLength;
|
||||||
uint64_t mRegionalTIDs[3];
|
|
||||||
std::vector<EPatchType> mPatchTypes;
|
|
||||||
void (*mPatchFunc)(EPatchType type);
|
|
||||||
};
|
};
|
||||||
|
WUT_CHECK_OFFSET(enl_RecordHeader, 0x00, mContentTransporterID);
|
||||||
|
WUT_CHECK_OFFSET(enl_RecordHeader, 0x01, mContentLength);
|
||||||
|
|
||||||
struct sead_String
|
struct enl_Buffer {
|
||||||
{
|
uint8_t *mData;
|
||||||
char *mBuffer;
|
size_t mCapacity;
|
||||||
uint32_t vtable;
|
size_t mSize;
|
||||||
|
bool isAllocated;
|
||||||
};
|
};
|
||||||
|
WUT_CHECK_OFFSET(enl_Buffer, 0x00, mData);
|
||||||
|
WUT_CHECK_OFFSET(enl_Buffer, 0x04, mCapacity);
|
||||||
|
WUT_CHECK_OFFSET(enl_Buffer, 0x08, mSize);
|
||||||
|
WUT_CHECK_OFFSET(enl_Buffer, 0x0C, isAllocated);
|
||||||
|
|
||||||
struct __attribute__((__packed__)) enl_RecordHeader
|
struct enl_ContentTransporter {
|
||||||
{
|
struct ContentTransporterVtbl {
|
||||||
uint8_t mContentTransporterID;
|
int a;
|
||||||
uint16_t mContentLength;
|
int b;
|
||||||
|
int f08;
|
||||||
|
void (*init)(enl_ContentTransporter *_this);
|
||||||
|
int _f10;
|
||||||
|
void *(*getSendBuffer)(enl_ContentTransporter *_this);
|
||||||
|
int _f18;
|
||||||
|
int (*getSendBufferSize)(enl_ContentTransporter *_this);
|
||||||
|
int _f20;
|
||||||
|
bool (*isNeedSend)(enl_ContentTransporter *_thiss);
|
||||||
|
int _f28;
|
||||||
|
unsigned char (*getContentID)(enl_ContentTransporter *_this);
|
||||||
|
// ...
|
||||||
|
};
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x00, a);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x04, b);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x08, f08);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x0C, init);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x10, _f10);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x14, getSendBuffer);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x18, _f18);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x1C, getSendBufferSize);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x20, _f20);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x24, isNeedSend);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x28, _f28);
|
||||||
|
WUT_CHECK_OFFSET(ContentTransporterVtbl, 0x2C, getContentID);
|
||||||
|
ContentTransporterVtbl *vtable;
|
||||||
};
|
};
|
||||||
|
WUT_CHECK_OFFSET(enl_ContentTransporter, 0x00, vtable);
|
||||||
|
|
||||||
struct enl_ContentTransporter
|
|
||||||
{
|
class PatchData {
|
||||||
struct ContentTransporterVtbl
|
public:
|
||||||
{
|
PatchData(std::string name, PatchedFunctionHandle handle) : name(std::move(name)), handle(handle) {
|
||||||
int a;
|
}
|
||||||
int b;
|
|
||||||
int f08;
|
std::string name;
|
||||||
void (*init)(enl_ContentTransporter *_this);
|
PatchedFunctionHandle handle;
|
||||||
int _f10;
|
|
||||||
void *(*getSendBuffer)(enl_ContentTransporter *_this);
|
|
||||||
int _f18;
|
|
||||||
int (*getSendBufferSize)(enl_ContentTransporter *_this);
|
|
||||||
int _f20;
|
|
||||||
bool (*isNeedSend)(enl_ContentTransporter *_thiss);
|
|
||||||
int _f28;
|
|
||||||
unsigned char (*getContentID)(enl_ContentTransporter *_this);
|
|
||||||
// ...
|
|
||||||
};
|
|
||||||
ContentTransporterVtbl *vtable;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ==========================================================================================
|
// ==========================================================================================
|
||||||
|
@ -75,26 +85,19 @@ struct enl_ContentTransporter
|
||||||
#define MARIO_KART_8_TID_U 0x000500001010EC00
|
#define MARIO_KART_8_TID_U 0x000500001010EC00
|
||||||
#define MARIO_KART_8_TID_E 0x000500001010ED00
|
#define MARIO_KART_8_TID_E 0x000500001010ED00
|
||||||
|
|
||||||
#define MARIO_KART_8_TID MARIO_KART_8_TID_J, MARIO_KART_8_TID_U, MARIO_KART_8_TID_E
|
#define MARIO_KART_8_TID MARIO_KART_8_TID_J, MARIO_KART_8_TID_U, MARIO_KART_8_TID_E
|
||||||
#define MARIO_KART_8_PATCHES PATCH_ENL_BUFFER_RCE, PATCH_ENL_ID_TOKEN_RCE
|
|
||||||
|
|
||||||
void MARIO_KART_8_ApplyPatch(EPatchType type);
|
bool MARIO_KART_8_AddPatches(std::vector<PatchData> &functionPatches);
|
||||||
|
|
||||||
// ==========================================================================================
|
// ==========================================================================================
|
||||||
|
|
||||||
#define SPLATOON_TID_J 0x0005000010162B00
|
#define SPLATOON_TID_J 0x0005000010162B00
|
||||||
#define SPLATOON_TID_U 0x0005000010176900
|
#define SPLATOON_TID_U 0x0005000010176900
|
||||||
#define SPLATOON_TID_E 0x0005000010176A00
|
#define SPLATOON_TID_E 0x0005000010176A00
|
||||||
|
|
||||||
#define SPLATOON_TID SPLATOON_TID_J, SPLATOON_TID_U, SPLATOON_TID_E
|
#define SPLATOON_TID SPLATOON_TID_J, SPLATOON_TID_U, SPLATOON_TID_E
|
||||||
#define SPLATOON_PATCHES PATCH_ENL_BUFFER_RCE
|
#define SPLATOON_PATCHES PATCH_ENL_BUFFER_RCE
|
||||||
|
|
||||||
void SPLATOON_ApplyPatch(EPatchType type);
|
bool SPLATOON_AddPatches(std::vector<PatchData> &functionPatches);
|
||||||
|
|
||||||
// ==========================================================================================
|
// ==========================================================================================
|
||||||
|
|
||||||
extern std::optional<rplinfo> gRPLInfo;
|
|
||||||
static std::vector<GamePatches> sGamePatchList = {
|
|
||||||
{"Mario Kart 8 ", {MARIO_KART_8_TID}, {MARIO_KART_8_PATCHES}, MARIO_KART_8_ApplyPatch},
|
|
||||||
{"Splatoon", {SPLATOON_TID}, {SPLATOON_PATCHES}, SPLATOON_ApplyPatch},
|
|
||||||
};
|
|
36
source/utils/logger.c
Normal file
36
source/utils/logger.c
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#ifdef DEBUG
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <whb/log_cafe.h>
|
||||||
|
#include <whb/log_module.h>
|
||||||
|
#include <whb/log_udp.h>
|
||||||
|
|
||||||
|
uint32_t moduleLogInit = false;
|
||||||
|
uint32_t cafeLogInit = false;
|
||||||
|
uint32_t udpLogInit = false;
|
||||||
|
#endif // DEBUG
|
||||||
|
|
||||||
|
void initLogging() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (!(moduleLogInit = WHBLogModuleInit())) {
|
||||||
|
cafeLogInit = WHBLogCafeInit();
|
||||||
|
udpLogInit = WHBLogUdpInit();
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
}
|
||||||
|
|
||||||
|
void deinitLogging() {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (moduleLogInit) {
|
||||||
|
WHBLogModuleDeinit();
|
||||||
|
moduleLogInit = false;
|
||||||
|
}
|
||||||
|
if (cafeLogInit) {
|
||||||
|
WHBLogCafeDeinit();
|
||||||
|
cafeLogInit = false;
|
||||||
|
}
|
||||||
|
if (udpLogInit) {
|
||||||
|
WHBLogUdpDeinit();
|
||||||
|
udpLogInit = false;
|
||||||
|
}
|
||||||
|
#endif // DEBUG
|
||||||
|
}
|
|
@ -1,29 +1,69 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <coreinit/debug.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <whb/log.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <string.h>
|
#define LOG_APP_TYPE "P"
|
||||||
#include <whb/log.h>
|
#define LOG_APP_NAME "rce_patches"
|
||||||
|
|
||||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||||
|
|
||||||
#define OSFATAL_FUNCTION_LINE(FMT, ARGS...) \
|
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", FMT, ##ARGS)
|
||||||
do { \
|
|
||||||
OSFatal_printf("[%s]%s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS)
|
||||||
|
|
||||||
|
#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \
|
||||||
|
do { \
|
||||||
|
LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
#ifdef DEBUG
|
||||||
do { \
|
|
||||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
|
||||||
} while (0);
|
|
||||||
|
|
||||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
|
#ifdef VERBOSE_DEBUG
|
||||||
do { \
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "", "", FMT, ##ARGS);
|
||||||
} while (0);
|
#else
|
||||||
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||||
|
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS)
|
||||||
|
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS)
|
||||||
|
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##INFO ## ", "", FMT, ##ARGS)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS);
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS)
|
||||||
|
#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS)
|
||||||
|
#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##INFO ## ", "\n", FMT, ##ARGS)
|
||||||
|
|
||||||
|
#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void initLogging();
|
||||||
|
|
||||||
|
void deinitLogging();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue