├── .github └── workflows │ ├── announce.yml │ └── build.yml ├── .gitignore ├── .vscode └── c_cpp_properties.json ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── data ├── gts.der └── rose_config.txt └── src ├── config.cpp ├── config.hpp ├── main.cpp ├── patches ├── aistFunction.cpp ├── fileReplacements.cpp ├── olvFix.cpp ├── olvFix.hpp ├── ssl.cpp ├── ssl.hpp ├── tviiIcon.cpp └── tviiIcon.hpp └── utils ├── Notification.cpp ├── Notification.hpp ├── logger.h ├── patch.cpp ├── patch.hpp ├── utils.cpp └── utils.hpp /.github/workflows/announce.yml: -------------------------------------------------------------------------------- 1 | name: Announce New Release 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | post: 9 | name: Send Announcement 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Announce 13 | shell: bash 14 | run: | 15 | curl \ 16 | -H "Content-Type: application/json" \ 17 | -d '{"content": "# Rosé Patcher ${{ github.event.release.tag_name }}\n-# A new version has been released!\n${CHANGELOG}\n\n${{ github.event.release.html_url }}\n||<@&${{ secrets.ROLE_ID }}>||", "username": "Rosé Patcher Updates", "avatar_url": "https://github.com/Project-Rose.png"}' \ 18 | ${{ secrets.WEBHOOK_URL }} 19 | env: 20 | CHANGELOG: ${{ github.event.release.body }} 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build Rosé Plugin for development and checks 2 | 3 | on: push 4 | 5 | jobs: 6 | build-plugin: 7 | name: Build Rosé Plugin 8 | runs-on: ubuntu-22.04 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: Build Toolchain Container 12 | run: docker build . -t builder 13 | - uses: ammaraskar/gcc-problem-matcher@master 14 | - name: Build Plugin 15 | run: docker run --rm -v ${PWD}:/app -w /app builder 16 | - uses: actions/upload-artifact@master 17 | with: 18 | name: devbuild 19 | path: "*.wps" 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | 3 | *.wps 4 | *.elf 5 | *.lst -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "defaultIncludePath": [ 4 | "${workspaceFolder}/build/**", 5 | "${workspaceFolder}/include/**", 6 | "${workspaceFolder}/source/**", 7 | "${workspaceFolder}/src/**" 8 | ], 9 | "defaultDefines": [], 10 | "DEVKITPROWIN": "C:/devkitPro", 11 | "cafeIncludePaths": [ 12 | "${env:DEVKITPRO}/portlibs/ppc/include/**", 13 | "${env:DEVKITPRO}/portlibs/wiiu/include/**", 14 | "${env:DEVKITPRO}/wut/include/**", 15 | "${env:DEVKITPRO}/wut/usr/include/**" 16 | ], 17 | "cafeIncludePathsWindows": [ 18 | "${env:DEVKITPROWIN}/portlibs/ppc/include/**", 19 | "${env:DEVKITPROWIN}/portlibs/wiiu/include/**", 20 | "${env:DEVKITPROWIN}/wut/include/**", 21 | "${env:DEVKITPROWIN}/wut/usr/include/**" 22 | ], 23 | "cafeDefines": [ 24 | "__WIIU__" 25 | ], 26 | "wupsIncludePaths": [ 27 | "${env:DEVKITPRO}/wups/include/**" 28 | ], 29 | "wupsIncludePathsWindows": [ 30 | "${env:DEVKITPROWIN}/wups/include/**" 31 | ], 32 | "wumsIncludePaths": [ 33 | "${env:DEVKITPRO}/wums/include/**" 34 | ], 35 | "wumsIncludePathsWindows": [ 36 | "${env:DEVKITPROWIN}/wums/include/**" 37 | ], 38 | "ppcCompilerPath": "${env:DEVKITPRO}/devkitPPC/bin/powerpc-eabi-g++", 39 | "ppcCompilerPathWindows": "${env:DEVKITPROWIN}/devkitPPC/bin/powerpc-eabi-g++" 40 | }, 41 | "configurations": [ 42 | { 43 | "name": "Wii U (Windows)", 44 | "includePath": [ 45 | "${env:defaultIncludePath}", 46 | "${env:cafeIncludePathsWindows}", 47 | "${env:wupsIncludePathsWindows}", 48 | "${env:wumsIncludePathsWindows}" 49 | ], 50 | "defines": [ 51 | "${env:defaultDefines}", 52 | "${env:cafeDefines}" 53 | ], 54 | "compilerPath": "${env:ppcCompilerPathWindows}", 55 | "cStandard": "c11", 56 | "cppStandard": "c++23", 57 | "intelliSenseMode": "linux-gcc-arm" 58 | }, 59 | { 60 | "name": "Wii U (Linux)", 61 | "includePath": [ 62 | "${env:defaultIncludePath}", 63 | "${env:cafeIncludePaths}", 64 | "${env:wupsIncludePaths}", 65 | "${env:wumsIncludePaths}" 66 | ], 67 | "defines": [ 68 | "${env:defaultDefines}", 69 | "${env:cafeDefines}" 70 | ], 71 | "compilerPath": "${env:ppcCompilerPath}", 72 | "cStandard": "c11", 73 | "cppStandard": "c++23", 74 | "intelliSenseMode": "linux-gcc-arm" 75 | } 76 | ], 77 | "version": 4 78 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/wiiu-env/devkitppc:20240505 2 | 3 | COPY --from=ghcr.io/wiiu-env/libnotifications:20240426 /artifacts $DEVKITPRO 4 | COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO 5 | COPY --from=ghcr.io/wiiu-env/libkernel:20230621 /artifacts $DEVKITPRO 6 | COPY --from=ghcr.io/wiiu-env/libmocha:20231127 /artifacts $DEVKITPRO 7 | COPY --from=ghcr.io/wiiu-env/wiiupluginsystem:20240505 /artifacts $DEVKITPRO 8 | 9 | WORKDIR /app 10 | CMD make -f Makefile -j$(nproc) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITPRO)),) 6 | $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | 11 | include $(DEVKITPRO)/wups/share/wups_rules 12 | 13 | WUT_ROOT := $(DEVKITPRO)/wut 14 | WUMS_ROOT := $(DEVKITPRO)/wums 15 | #------------------------------------------------------------------------------- 16 | # TARGET is the name of the output 17 | # BUILD is the directory where object files & intermediate files will be placed 18 | # SOURCES is a list of directories containing source code 19 | # DATA is a list of directories containing data files 20 | # INCLUDES is a list of directories containing header files 21 | #------------------------------------------------------------------------------- 22 | TARGET := RosePatcher 23 | BUILD := build 24 | SOURCES := src src/utils src/patches 25 | DATA := data 26 | INCLUDES := src 27 | 28 | #------------------------------------------------------------------------------- 29 | # options for code generation 30 | #------------------------------------------------------------------------------- 31 | CFLAGS := -g -Wall -O2 -ffunction-sections \ 32 | $(MACHDEP) 33 | 34 | CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__ 35 | 36 | CXXFLAGS := $(CFLAGS) -std=c++23 37 | 38 | ASFLAGS := -g $(ARCH) 39 | LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -T$(WUMS_ROOT)/share/libkernel.ld $(WUPSSPECS) 40 | 41 | LIBS := -lwups -lnotifications -lfunctionpatcher -lwut -lkernel 42 | 43 | #------------------------------------------------------------------------------- 44 | # list of directories containing libraries, this must be the top level 45 | # containing include and lib 46 | #------------------------------------------------------------------------------- 47 | LIBDIRS := $(PORTLIBS) $(WUPS_ROOT) $(WUMS_ROOT) $(WUT_ROOT) $(WUT_ROOT)/usr 48 | 49 | #------------------------------------------------------------------------------- 50 | # no real need to edit anything past this point unless you need to add additional 51 | # rules for different file extensions 52 | #------------------------------------------------------------------------------- 53 | ifneq ($(BUILD),$(notdir $(CURDIR))) 54 | #------------------------------------------------------------------------------- 55 | 56 | export OUTPUT := $(CURDIR)/$(TARGET) 57 | export TOPDIR := $(CURDIR) 58 | 59 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 60 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 61 | 62 | export DEPSDIR := $(CURDIR)/$(BUILD) 63 | 64 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 65 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 66 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 67 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 68 | 69 | #------------------------------------------------------------------------------- 70 | # use CXX for linking C++ projects, CC for standard C 71 | #------------------------------------------------------------------------------- 72 | ifeq ($(strip $(CPPFILES)),) 73 | #------------------------------------------------------------------------------- 74 | export LD := $(CC) 75 | #------------------------------------------------------------------------------- 76 | else 77 | #------------------------------------------------------------------------------- 78 | export LD := $(CXX) 79 | #------------------------------------------------------------------------------- 80 | endif 81 | #------------------------------------------------------------------------------- 82 | 83 | export OFILES_BIN := $(addsuffix .o,$(BINFILES)) 84 | export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 85 | export OFILES := $(OFILES_BIN) $(OFILES_SRC) 86 | export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) 87 | 88 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 89 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 90 | -I$(CURDIR)/$(BUILD) 91 | 92 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 93 | 94 | .PHONY: $(BUILD) clean all 95 | 96 | #------------------------------------------------------------------------------- 97 | all: $(BUILD) 98 | 99 | $(BUILD): 100 | @[ -d $@ ] || mkdir -p $@ 101 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 102 | 103 | #------------------------------------------------------------------------------- 104 | clean: 105 | @echo clean ... 106 | @rm -fr $(BUILD) $(TARGET).wps $(TARGET).elf 107 | 108 | #------------------------------------------------------------------------------- 109 | run: # need wiiload + wiiload plugin on the Wii U (get plugin at https://aroma.foryour.cafe/) 110 | # ^^^^ (I don't know if it comes pre-installed with devkitpro without having the wii portion installed, so you can also get it from the hackmii installer https://bootmii.org/download) 111 | @wiiload $(TARGET).wps 112 | 113 | #------------------------------------------------------------------------------- 114 | else 115 | .PHONY: all 116 | 117 | DEPENDS := $(OFILES:.o=.d) 118 | 119 | #------------------------------------------------------------------------------- 120 | # main targets 121 | #------------------------------------------------------------------------------- 122 | all : $(OUTPUT).wps 123 | 124 | $(OUTPUT).wps : $(OUTPUT).elf 125 | $(OUTPUT).elf : $(OFILES) 126 | 127 | $(OFILES_SRC) : $(HFILES_BIN) 128 | 129 | #------------------------------------------------------------------------------- 130 | # you need a rule like this for each extension you use as binary data 131 | #------------------------------------------------------------------------------- 132 | %.bin.o %_bin.h : %.bin 133 | #------------------------------------------------------------------------------- 134 | @echo $(notdir $<) 135 | @$(bin2o) 136 | 137 | %.txt.o %_txt.h : %.txt 138 | #------------------------------------------------------------------------------- 139 | @echo $(notdir $<) 140 | @$(bin2o) 141 | 142 | %.der.o %_der.h : %.der 143 | #------------------------------------------------------------------------------- 144 | @echo $(notdir $<) 145 | @$(bin2o) 146 | 147 | %.pem.o %_pem.h : %.pem 148 | #------------------------------------------------------------------------------- 149 | @echo $(notdir $<) 150 | @$(bin2o) 151 | 152 | -include $(DEPENDS) 153 | 154 | 155 | #------------------------------------------------------------------------------- 156 | endif 157 | #------------------------------------------------------------------------------- 158 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rosé Patcher (Name subject to change) 2 | This is Rosé Patcher! The Aroma plugin that revives Nintendo TVii icon from the Wii U Menu and Home Menu, as well as the applet from inside! 3 | 4 | 5 | ## Credits 6 | - [Cooper](https://github.com/coopeeo) ([@coopeeo](https://github.com/coopeeo)): Lead Plugin Developer - TVii Config, Acquire Independent Service Token (<-- hi cooper here to say this was absolute hell), and plugin settings. 7 | - [Swirlz](https://github.com/itzswirlz) ([@ItzSwirlz](https://github.com/itzswirls)): Plugin Developer - Helped a lot with issues (and cooper's dumb brain). 8 | - All the other people in the Aroma Discord (because of cooper not understanding anything and being an idiot). 9 | - [@darcellapy](https://github.com/darcellapy): For the original [Vino Config Patcher](https://github.com/darcellapy/vino-config-patcher-plugin) 10 | - All the other people who worked on this project, you can see them at [projectrose.cafe](https://projectrose.cafe) 11 | - Also all the other contributers 12 | - [Pretendo](https://pretendo.network)/[Ash](https://github.com/ashquarky) ([@ashquarky](https://github.com/ashquarky)) for CI/Building with GitHub Actions. (Notice: we are not affiliated with Pretendo, nor do they endorse us. I also simply took the things that Ash did and replicated it here.) 13 | 14 | ## Help 15 | 16 | ### My console is crashing at the Wii U Menu! I also have a Japan console! 17 | Well we were not able to detect your console automatically, so on your sd card, go to sd card > wiiu > environments > aroma > plugins > config, and then open the the file named rosepatcher.json. After you have opened the file, change the force_jpn_console value from false to true 18 | -------------------------------------------------------------------------------- /data/gts.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Project-Rose/RosePatcher/e40fef15b05f611b80b0c3a1158f73e945bd4ef6/data/gts.der -------------------------------------------------------------------------------- /data/rose_config.txt: -------------------------------------------------------------------------------- 1 | #ur0 is default 2 | url0:https://tvii-prod.l1.us.vino.wup.app.projectrose.cafe/ 3 | 4 | # on/off debug print of client 5 | CallbackDebugPrint:0 6 | 7 | # add timestamp to debug print 8 | AddTimeStampToDebugPrint:0 9 | 10 | # 0/1 download whitelist with/without Verifying service-token 11 | # 0 download the white-list without service-token on http-request-header 12 | # 1 download the white-list with service-token on http-request-header 13 | WhiteList_VerifyServiceToken:1 14 | 15 | # 0/1 use whitelist cache on NAND 16 | WhiteList_UseCache:0 17 | 18 | # on/off javascript error print on console 19 | # 0:off, 1:on 20 | JavaScriptErrorPrintOnConsole:0 21 | 22 | # on/off javascript error print on dialog 23 | # 0:off, 1:on 24 | JavaScriptErrorPrintOnDialog:0 25 | 26 | # on/off console.log()[javascript] print on console 27 | # 0:off, 1:on 28 | ConsoleLogPrint:0 29 | 30 | # 0/1/2 TV rendering style 31 | # 0:Development (display DRC-screen with some debug information) 32 | # 1:Demo (display only DRC-screen at center) 33 | # 2:Final (display nothing) 34 | TVStyle:2 35 | 36 | #LoadUrl 37 | # 0: Load from WhiteList (If not exist, load from url0.) 38 | # 1: Load from url0 39 | LoadUrl:1 40 | 41 | # 0/1 FriendList Contains Temporary Friend and Requested Friend or not. 42 | # 0:Not Contain 43 | # 1:Contain 44 | ContainTemporaryFriend:0 45 | 46 | # 0/1 Reset Navi Forcus on Drag Event 47 | # 0:Disable (don't reset on drag event) 48 | # 1:Enable (reset on drag event) 49 | NaviResetOnDrag:0 50 | 51 | # Enable Accelearted Compositing 52 | # 0 : Disable 53 | # 1 : Enable 54 | EnableAc:1 55 | 56 | # Enable Event Lock at Page Loading 57 | # 0 : Disable 58 | # 1 : Enable 59 | EnableEventLock:1 60 | 61 | # User Agent Setting 62 | # UserAgent_String: Mozilla/5.0 (Nintendo WiiU) AppleWebKit/534.52 (KHTML, like Gecko) NX/ 63 | # 0/1/2/3 WhiteList Setting. 64 | # 0:None (vino does not use white-list) 65 | # 1:File (vino uses white-list on file, path is written at 'WhiteList_Path') 66 | # 2:Network (vino uses white-list on network, path is written at 'WhiteList_Path'. in this mode, white-list is downloaded with a paticular ssl certification for client and server.) 67 | # 3:Release (vino uses the final environment by each region.) 68 | WhiteList_Use:0 69 | WhiteList_Path:https://web-jp.l1.jp.vino.wup.app.projectrose.cafe/whitelist.txt?country=us 70 | 71 | # Allow 'file:' and 'http:' scheme. Finally, it is set to 'Not Allow' 72 | # 0:Not Allow 73 | # 1:Allow 74 | AllowDebugScheme:0 75 | 76 | # LoadingIcon 77 | # 0:Not Draw Icon at Pre-loading 78 | # 1:Draw 79 | PreLoadIconDraw:1 80 | 81 | # Navigation to Minus Location 82 | # 0:Not Allow 83 | # 1:Allow 84 | EnableNaviMinusLocation:1 85 | 86 | PreLoadIconLeft:797 87 | PreLoadIconTop:424 88 | PreLoadIconWidth:82 89 | PreLoadIconHeight:82 90 | PreLoadIconWaitingFrame:1 91 | 92 | # LayoutColor RGB (0-255) 93 | 94 | 95 | P_TouchEffectSBColorR:255 96 | P_TouchEffectSBColorG:30 97 | P_TouchEffectSBColorB:42 98 | P_TouchEffectSWColorR:255 99 | P_TouchEffectSWColorG:30 100 | P_TouchEffectSWColorB:42 101 | 102 | P_TouchEffectMBColorR:255 103 | P_TouchEffectMBColorG:31 104 | P_TouchEffectMBColorB:38 105 | P_TouchEffectMWColorR:255 106 | P_TouchEffectMWColorG:48 107 | P_TouchEffectMWColorB:58 108 | 109 | W_NodeFrameBColorR:255 110 | W_NodeFrameBColorG:41 111 | W_NodeFrameBColorB:76 112 | W_NodeFrameWColorR:255 113 | W_NodeFrameWColorG:122 114 | W_NodeFrameWColorB:128 115 | W_NodeFrameVTColorR:255 116 | W_NodeFrameVTColorG:247 117 | W_NodeFrameVTColorB:249 118 | W_NodeFrameVBColorR:255 119 | W_NodeFrameVBColorG:224 120 | W_NodeFrameVBColorB:236 121 | 122 | W_BaseBColorR:255 123 | W_BaseBColorG:41 124 | W_BaseBColorB:76 125 | W_BaseWColorR:255 126 | W_BaseWColorG:122 127 | W_BaseWColorB:128 128 | W_BaseVTColorR:255 129 | W_BaseVTColorG:247 130 | W_BaseVTColorB:249 131 | W_BaseVBColorR:255 132 | W_BaseVBColorG:224 133 | W_BaseVBColorB:236 134 | 135 | W_DecideWColorR:255 136 | W_DecideWColorG:184 137 | W_DecideWColorB:205 138 | -------------------------------------------------------------------------------- /src/config.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "config.hpp" 18 | #include "utils/utils.hpp" 19 | #include "utils/logger.h" 20 | 21 | namespace config { 22 | std::string replacementToken; 23 | bool connectToRose = CONNECT_TO_ROSE_DEFUALT_VALUE; 24 | bool tviiIconHBM = TVII_ICON_HBM_PATCH_DEFAULT_VALUE; 25 | bool tviiIconWUM = TVII_ICON_WUM_PATCH_DEFAULT_VALUE; 26 | bool forceJPNconsole = FORCE_JPN_CONSOLE_DEFAULT_VALUE; 27 | bool needRelaunch = false; 28 | 29 | // Connect to Rose setting event 30 | void connectToRoseChanged(ConfigItemBoolean *item, bool newValue) { 31 | if (newValue != connectToRose) { 32 | WUPSStorageAPI::Store(CONNECT_TO_ROSE_CONFIG_ID, newValue); 33 | } 34 | 35 | connectToRose = newValue; 36 | } 37 | 38 | void tviiIconHBMChanged(ConfigItemBoolean *item, bool newValue) { 39 | if (tviiIconHBM != newValue) { 40 | WUPSStorageAPI::Store(TVII_ICON_HBM_PATCH_COFNIG_ID, newValue); 41 | } 42 | 43 | tviiIconHBM = newValue; 44 | } 45 | 46 | void tviiIconWUMChanged(ConfigItemBoolean *item, bool newValue) { 47 | if (tviiIconWUM != newValue) { 48 | WUPSStorageAPI::Store(TVII_ICON_WUM_PATCH_COFNIG_ID, newValue); 49 | } 50 | 51 | tviiIconWUM = newValue; 52 | auto title = OSGetTitleID(); 53 | if (utils::isWiiUMenuTitleID(title, false)) { 54 | needRelaunch = true; 55 | } 56 | } 57 | 58 | // Open event for the Aroma config menu 59 | WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle) { 60 | WUPSConfigCategory root = WUPSConfigCategory(rootHandle); 61 | 62 | try { 63 | // Add setting items 64 | root.add(WUPSConfigItemStub::Create("-- General --")); 65 | root.add(WUPSConfigItemBoolean::Create(CONNECT_TO_ROSE_CONFIG_ID, "Connect to Rosé", CONNECT_TO_ROSE_DEFUALT_VALUE, connectToRose, connectToRoseChanged)); 66 | 67 | if (!utils::isJapanConsole()) { 68 | root.add(WUPSConfigItemStub::Create("-- TVii Icons --")); 69 | root.add(WUPSConfigItemBoolean::Create(TVII_ICON_HBM_PATCH_COFNIG_ID, "Add TVii Icon to the \ue073 Menu", TVII_ICON_HBM_PATCH_DEFAULT_VALUE, tviiIconHBM, tviiIconHBMChanged)); 70 | root.add(WUPSConfigItemBoolean::Create(TVII_ICON_WUM_PATCH_COFNIG_ID, "Add TVii Icon to the Wii U Menu", TVII_ICON_WUM_PATCH_DEFAULT_VALUE, tviiIconWUM, tviiIconWUMChanged)); 71 | root.add(WUPSConfigItemStub::Create("Note: Wii U Menu will restart if \"Add TVii Icon to the Wii U Menu\"")); 72 | root.add(WUPSConfigItemStub::Create("is toggled.")); 73 | } 74 | } catch (std::exception &e) { 75 | DEBUG_FUNCTION_LINE("Creating config menu failed: %s", e.what()); 76 | return WUPSCONFIG_API_CALLBACK_RESULT_ERROR; 77 | } 78 | 79 | return WUPSCONFIG_API_CALLBACK_RESULT_SUCCESS; 80 | } 81 | 82 | // Close event for the Aroma config menu 83 | void ConfigMenuClosedCallback() { 84 | WUPSStorageAPI::SaveStorage(); 85 | if (needRelaunch) { 86 | _SYSLaunchTitleWithStdArgsInNoSplash(OSGetTitleID(), nullptr); 87 | needRelaunch = false; 88 | } 89 | } 90 | 91 | // Config stuff in plugin initialization 92 | void InitializeConfig() { 93 | // Add the config 94 | WUPSConfigAPIOptionsV1 configOptions = {.name = "Rosé Patcher"}; 95 | if (WUPSConfigAPI_Init(configOptions, ConfigMenuOpenedCallback, 96 | ConfigMenuClosedCallback) != 97 | WUPSCONFIG_API_RESULT_SUCCESS) { 98 | DEBUG_FUNCTION_LINE("Failed to init config api"); 99 | } 100 | 101 | // Add get saved values 102 | WUPSStorageError storageRes; 103 | if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(CONNECT_TO_ROSE_CONFIG_ID, connectToRose, CONNECT_TO_ROSE_DEFUALT_VALUE)) != WUPS_STORAGE_ERROR_SUCCESS) { 104 | DEBUG_FUNCTION_LINE("GetOrStoreDefault failed: %s (%d)", WUPSStorageAPI_GetStatusStr(storageRes), storageRes); 105 | } 106 | if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(TVII_ICON_HBM_PATCH_COFNIG_ID, tviiIconHBM, TVII_ICON_HBM_PATCH_DEFAULT_VALUE)) != WUPS_STORAGE_ERROR_SUCCESS) { 107 | DEBUG_FUNCTION_LINE("GetOrStoreDefault failed: %s (%d)", WUPSStorageAPI_GetStatusStr(storageRes), storageRes); 108 | } 109 | if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(TVII_ICON_WUM_PATCH_COFNIG_ID, tviiIconWUM, TVII_ICON_WUM_PATCH_DEFAULT_VALUE)) != WUPS_STORAGE_ERROR_SUCCESS) { 110 | DEBUG_FUNCTION_LINE("GetOrStoreDefault failed: %s (%d)", WUPSStorageAPI_GetStatusStr(storageRes), storageRes); 111 | } 112 | 113 | // For when we can't detect someones console region and their console region is actually Japan 114 | if ((storageRes = WUPSStorageAPI::GetOrStoreDefault(FORCE_JPN_CONSOLE_CONFIG_ID, forceJPNconsole, FORCE_JPN_CONSOLE_DEFAULT_VALUE)) != WUPS_STORAGE_ERROR_SUCCESS) { 115 | DEBUG_FUNCTION_LINE("GetOrStoreDefault failed: %s (%d)", WUPSStorageAPI_GetStatusStr(storageRes), storageRes); 116 | } 117 | 118 | int handle = MCP_Open(); 119 | MCPSysProdSettings settings alignas(0x40); 120 | MCPError error = MCP_GetSysProdSettings(handle, &settings); 121 | if(error) { 122 | replacementToken = ""; 123 | DEBUG_FUNCTION_LINE("MCP_GetSysProdSettings failed"); 124 | } 125 | 126 | MCP_Close(handle); 127 | 128 | nn::act::PrincipalId pid = nn::act::GetPrincipalId(); 129 | replacementToken = std::format("[0000, {}, {:d}, 000]", settings.serial_id, pid); 130 | reverse(std::next(replacementToken.begin()), std::prev(replacementToken.end())); 131 | } 132 | 133 | } // namespace config 134 | -------------------------------------------------------------------------------- /src/config.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define CONNECT_TO_ROSE_CONFIG_ID "connect_to_rose" 14 | #define CONNECT_TO_ROSE_DEFUALT_VALUE true 15 | 16 | #define TVII_ICON_HBM_PATCH_COFNIG_ID "tvii_icon_hbm_patch" 17 | #define TVII_ICON_HBM_PATCH_DEFAULT_VALUE true 18 | 19 | #define TVII_ICON_WUM_PATCH_COFNIG_ID "tvii_icon_wum_patch" 20 | #define TVII_ICON_WUM_PATCH_DEFAULT_VALUE true 21 | 22 | #define FORCE_JPN_CONSOLE_CONFIG_ID "force_jpn_console" 23 | #define FORCE_JPN_CONSOLE_DEFAULT_VALUE false 24 | 25 | 26 | 27 | namespace config { 28 | // This isn't configuration, but we need to create the replacement token ASAP 29 | // since I don't think we can generate it while in vino -ItzSwirlz 30 | extern std::string replacementToken; 31 | 32 | extern bool connectToRose; 33 | extern bool tviiIconHBM; 34 | extern bool tviiIconWUM; 35 | extern bool needRelaunch; 36 | extern bool forceJPNconsole; 37 | 38 | void connectToRoseChanged(ConfigItemBoolean *item, bool newValue); 39 | void tviiIconHBMChanged(ConfigItemBoolean *item, bool newValue); 40 | void tviiIconWUMChanged(ConfigItemBoolean *item, bool newValue); 41 | 42 | WUPSConfigAPICallbackStatus ConfigMenuOpenedCallback(WUPSConfigCategoryHandle rootHandle); 43 | 44 | void ConfigMenuClosedCallback(); 45 | void InitializeConfig(); 46 | } // namespace config 47 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "config.hpp" 8 | #include "patches/tviiIcon.hpp" 9 | #include "utils/Notification.hpp" 10 | #include "utils/logger.h" 11 | 12 | WUPS_PLUGIN_NAME("Rosé Patcher"); 13 | WUPS_PLUGIN_DESCRIPTION("Patcher for Project Rosé's Nintendo TVii revival service."); 14 | WUPS_PLUGIN_VERSION("v1.1.0"); 15 | WUPS_PLUGIN_AUTHOR("Project Rosé Team"); 16 | WUPS_PLUGIN_LICENSE("GPLv2"); 17 | 18 | WUPS_USE_STORAGE("rosepatcher"); 19 | WUPS_USE_WUT_DEVOPTAB(); 20 | 21 | INITIALIZE_PLUGIN() { 22 | // Initialize libraries 23 | WHBLogModuleInit(); 24 | WHBLogUdpInit(); 25 | WHBLogCafeInit(); 26 | nn::act::Initialize(); 27 | FunctionPatcher_InitLibrary(); 28 | 29 | config::InitializeConfig(); 30 | 31 | // Check if NotificationModule library is initialized 32 | if (NotificationModule_InitLibrary() != NOTIFICATION_MODULE_RESULT_SUCCESS) { 33 | DEBUG_FUNCTION_LINE("NotificationModule_InitLibrary failed"); 34 | } 35 | 36 | if (config::connectToRose) { 37 | ShowNotification("Rosé patch enabled"); 38 | } else { 39 | ShowNotification("Rosé patch disabled"); 40 | } 41 | } 42 | 43 | DEINITIALIZE_PLUGIN() { 44 | patches::icon::perform_hbm_patches(false); 45 | 46 | nn::act::Finalize(); 47 | WHBLogModuleDeinit(); 48 | WHBLogUdpDeinit(); 49 | WHBLogCafeDeinit(); 50 | NotificationModule_DeInitLibrary(); 51 | FunctionPatcher_DeInitLibrary(); 52 | } 53 | 54 | ON_APPLICATION_START() { 55 | WHBLogModuleInit(); 56 | WHBLogUdpInit(); 57 | WHBLogCafeInit(); 58 | 59 | auto title = OSGetTitleID(); 60 | if (config::tviiIconWUM) { 61 | if (title == 0x5001010040000 || title == 0x5001010040100 || title == 0x5001010040200) { 62 | patches::icon::perform_men_patches(true); 63 | } 64 | } 65 | } 66 | 67 | ON_APPLICATION_ENDS() { 68 | auto title = OSGetTitleID(); 69 | if (title == 0x5001010040000 || title == 0x5001010040100 || title == 0x5001010040200) { 70 | patches::icon::perform_men_patches(false); 71 | } 72 | } -------------------------------------------------------------------------------- /src/patches/aistFunction.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | #include "ssl.hpp" 13 | #include "../config.hpp" 14 | #include "../utils/Notification.hpp" 15 | #include "../utils/logger.h" 16 | #include "../utils/utils.hpp" 17 | #include "../utils/patch.hpp" 18 | 19 | PatchedFunctionHandle AISTpatchHandleBetter = 0; 20 | int AISTCallCount = 0; 21 | 22 | DECL_FUNCTION(int, AcquireIndependentServiceToken__Q2_2nn3actFPcPCcUibT4, uint8_t* token, const char* client_id) { 23 | if (client_id && utils::isVinoClientID(client_id) && config::connectToRose) { 24 | AISTCallCount++; 25 | DEBUG_FUNCTION_LINE("AISTCallCount is %d!", AISTCallCount); 26 | patches::ssl::addCertificateToWebKit(); 27 | DEBUG_FUNCTION_LINE("Faking service sucess for '%s' (should be Vino)", client_id); 28 | memcpy(token, config::replacementToken.c_str(), config::replacementToken.size()); 29 | return 0; 30 | } 31 | 32 | // make sure we set the token again in case the following replaces it just in case 33 | return real_AcquireIndependentServiceToken__Q2_2nn3actFPcPCcUibT4(token, client_id); 34 | } 35 | 36 | DECL_FUNCTION(void, NSSLInit) 37 | { 38 | OSDynLoad_Module NN_ACT = 0; 39 | uint32_t AISTaddressVIR = 0; 40 | uint32_t AISTaddress = 0; 41 | bool isAlreadyPatched = false; 42 | PatchedFunctionHandle AISTpatchHandle = 0; 43 | bool AISTpatchSuccess = false; 44 | 45 | // Call the original function 46 | real_NSSLInit(); 47 | 48 | // Init Logging Functions 49 | WHBLogModuleInit(); 50 | WHBLogUdpInit(); 51 | WHBLogCafeInit(); 52 | 53 | // Notify about the patch 54 | DEBUG("Rosé Patcher: Trying to patch AcquireIndependentServiceToken via NSSLInit\n"); 55 | 56 | FunctionPatcher_IsFunctionPatched(AISTpatchHandleBetter, &isAlreadyPatched); 57 | 58 | DEBUG_FUNCTION_LINE("AISTCallCount is %d!", AISTCallCount); 59 | 60 | if (AISTCallCount >= 3) { 61 | DEBUG_FUNCTION_LINE("AISTCallCount is %d, removing patch...", AISTCallCount); 62 | AISTCallCount = 0; 63 | FunctionPatcher_RemoveFunctionPatch(AISTpatchHandleBetter); 64 | } else if (isAlreadyPatched == true) { 65 | DEBUG_FUNCTION_LINE("AISTCallCount is %d, but we got true of isalreadypatched so return.", AISTCallCount); 66 | AISTCallCount = 0; 67 | FunctionPatcher_RemoveFunctionPatch(AISTpatchHandleBetter); 68 | //return; 69 | } 70 | 71 | if (!config::connectToRose) { 72 | DEBUG_FUNCTION_LINE("\"Connect to Rosé\" patch is disabled, skipping..."); 73 | return; 74 | } 75 | 76 | // Acquire the nn_act module 77 | if(OSDynLoad_Acquire("nn_act.rpl", &NN_ACT) != OS_DYNLOAD_OK) { 78 | DEBUG_FUNCTION_LINE("Failed to acquire nn_act.rpl module."); 79 | return; 80 | } 81 | 82 | // Find the AcquireIndependentServiceToken function addresses 83 | if(OSDynLoad_FindExport(NN_ACT, OS_DYNLOAD_EXPORT_FUNC, "AcquireIndependentServiceToken__Q2_2nn3actFPcPCcUibT4", (void**)&AISTaddressVIR) != OS_DYNLOAD_OK) { // Get the physical address 84 | DEBUG_FUNCTION_LINE("Failed to find AcquireIndependentServiceToken function in nn_act.rpl"); 85 | OSDynLoad_Release(NN_ACT); 86 | return; 87 | } 88 | AISTaddress = OSEffectiveToPhysical(AISTaddressVIR); // Get the virtual address 89 | 90 | // Show results of the AcquireIndependentServiceToken function address findings 91 | // DEBUG("AcquireIndependentServiceToken__Q2_2nn3actFPcPCcUibT4 results\n" 92 | // "Rosé Patcher: Physical Address: %d\n" 93 | // "Rosé Patcher: Virtual Address: %d\n" 94 | // "Rosé Patcher: -- END OF AcquireIndependentServiceToken ADDRESS RESULTS --", 95 | // &AISTaddress, &AISTaddressVIR); 96 | 97 | // Make function replacement data 98 | function_replacement_data_t AISTpatch = REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS( 99 | AcquireIndependentServiceToken__Q2_2nn3actFPcPCcUibT4, 100 | AISTaddress, 101 | AISTaddressVIR, 102 | FP_TARGET_PROCESS_TVII); 103 | 104 | // Patch the function 105 | if(FunctionPatcher_AddFunctionPatch(&AISTpatch, &AISTpatchHandle, &AISTpatchSuccess) != FunctionPatcherStatus::FUNCTION_PATCHER_RESULT_SUCCESS) { 106 | DEBUG_FUNCTION_LINE("Failed to add patch."); 107 | OSDynLoad_Release(NN_ACT); 108 | return; 109 | } 110 | 111 | AISTpatchHandleBetter = AISTpatchHandle; 112 | 113 | if (AISTpatchSuccess == false) { 114 | DEBUG_FUNCTION_LINE("Failed to add patch."); 115 | OSDynLoad_Release(NN_ACT); 116 | return; 117 | } 118 | 119 | // Notify about the patch success 120 | DEBUG("Patched AcquireIndependentServiceToken via NSSLInit"); 121 | OSDynLoad_Release(NN_ACT); 122 | } 123 | 124 | WUPS_MUST_REPLACE_FOR_PROCESS(NSSLInit, WUPS_LOADER_LIBRARY_NSYSNET, NSSLInit, WUPS_FP_TARGET_PROCESS_TVII); 125 | -------------------------------------------------------------------------------- /src/patches/fileReplacements.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../config.hpp" 5 | #include "../utils/Notification.hpp" 6 | #include "../utils/logger.h" 7 | #include "../utils/patch.hpp" 8 | 9 | #include "rose_config_txt.h" // included at runtime 10 | 11 | #define VINO_CONFIG_PATH "/vol/content/vino_config.txt" 12 | 13 | static std::optional config_handle{}; 14 | 15 | DECL_FUNCTION(FSStatus, FSOpenFile_VINO, FSClient *client, FSCmdBlock *block, 16 | const char *path, const char *mode, FSFileHandle *handle, 17 | FSErrorFlag errorMask) { 18 | 19 | // DEBUG("Wii U wants to open file: %s", path); 20 | 21 | if (config::connectToRose && strcmp(VINO_CONFIG_PATH, path) == 0) { 22 | FSStatus res = real_FSOpenFile_VINO(client, block, path, mode, handle, errorMask); 23 | config_handle = *handle; 24 | return res; 25 | } 26 | 27 | return real_FSOpenFile_VINO(client, block, path, mode, handle, errorMask); 28 | } 29 | 30 | DECL_FUNCTION(FSStatus, FSReadFile_VINO, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, 31 | FSFileHandle handle, uint32_t unk1, uint32_t flags) { 32 | if (size != 1) { 33 | DEBUG_FUNCTION_LINE("Falied to patch vino config. Size is not 1"); 34 | } 35 | 36 | if (config_handle && *config_handle == handle) { 37 | DEBUG_FUNCTION_LINE("Trying to read vino config detected, returning patched data."); 38 | strlcpy((char *) buffer, (const char *) rose_config_txt, size * count); 39 | return (FSStatus) count; 40 | } 41 | 42 | return real_FSReadFile_VINO(client, block, buffer, size, count, handle, unk1, flags); 43 | } 44 | 45 | DECL_FUNCTION(FSStatus, FSCloseFile_VINO, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) { 46 | if (handle == config_handle) { 47 | DEBUG("Closing Vino config file and resetting handle"); 48 | config_handle.reset(); 49 | } 50 | 51 | return real_FSCloseFile_VINO(client, block, handle, errorMask); 52 | } 53 | 54 | WUPS_MUST_REPLACE_FOR_PROCESS(FSOpenFile_VINO, WUPS_LOADER_LIBRARY_COREINIT, FSOpenFile, WUPS_FP_TARGET_PROCESS_TVII); 55 | WUPS_MUST_REPLACE_FOR_PROCESS(FSReadFile_VINO, WUPS_LOADER_LIBRARY_COREINIT, FSReadFile, WUPS_FP_TARGET_PROCESS_TVII); 56 | WUPS_MUST_REPLACE_FOR_PROCESS(FSCloseFile_VINO, WUPS_LOADER_LIBRARY_COREINIT, FSCloseFile, WUPS_FP_TARGET_PROCESS_TVII); 57 | -------------------------------------------------------------------------------- /src/patches/olvFix.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "olvFix.hpp" 11 | #include "../config.hpp" 12 | #include "../utils/patch.hpp" 13 | #include "../utils/logger.h" 14 | 15 | namespace patches::olv { 16 | const char original_discovery_url[] = "discovery.olv.nintendo.net/v1/endpoint"; 17 | const char new_discovery_url[] = "discovery.olv.pretendo.cc/v1/endpoint"; 18 | 19 | void osdynload_notify_callback(OSDynLoad_Module module, void *ctx, 20 | OSDynLoad_NotifyReason reason, OSDynLoad_NotifyData *rpl) { 21 | if (reason == OS_DYNLOAD_NOTIFY_LOADED) { 22 | if (!rpl->name) 23 | return; 24 | 25 | if (!std::string_view(rpl->name).ends_with("nn_olv.rpl") || !config::connectToRose) 26 | return; 27 | 28 | 29 | utils::patch::replace_mem(rpl->dataAddr, rpl->dataSize, original_discovery_url, 30 | sizeof(original_discovery_url), new_discovery_url, sizeof(new_discovery_url)); 31 | } 32 | } 33 | 34 | DECL_FUNCTION(int, FSOpenFile, FSClient *pClient, FSCmdBlock *pCmd, 35 | const char *path, const char *mode, int *handle, int error) { 36 | if (strcmp("/vol/content/vino_config.txt", path) == 0) { 37 | OSDynLoad_AddNotifyCallback(&osdynload_notify_callback, nullptr); 38 | } 39 | 40 | return real_FSOpenFile(pClient, pCmd, path, mode, handle, error);; 41 | } 42 | 43 | WUPS_MUST_REPLACE_FOR_PROCESS(FSOpenFile, WUPS_LOADER_LIBRARY_COREINIT, FSOpenFile, WUPS_FP_TARGET_PROCESS_TVII); 44 | } // namespace olv 45 | -------------------------------------------------------------------------------- /src/patches/olvFix.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "../utils/logger.h" 5 | 6 | namespace patches::olv { 7 | extern const char original_discovery_url[]; 8 | extern const char new_discovery_url[]; 9 | 10 | void osdynload_notify_callback(OSDynLoad_Module module, void *ctx, 11 | OSDynLoad_NotifyReason reason, OSDynLoad_NotifyData *rpl); 12 | } // namespace olv -------------------------------------------------------------------------------- /src/patches/ssl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "ssl.hpp" 6 | 7 | #include "../utils/Notification.hpp" 8 | #include "../utils/logger.h" 9 | #include "../utils/patch.hpp" 10 | #include "../config.hpp" 11 | 12 | #include "gts_der.h" // Included at runtime 13 | 14 | namespace patches::ssl { 15 | void addCertificateToWebKit() { 16 | OSDynLoad_Module libwkc = 0; 17 | void* (*WKC_SSLRegisterRootCAByDER)(const char* cert, int cert_len) = nullptr; 18 | 19 | if (!config::connectToRose) { 20 | return; 21 | } 22 | 23 | OSDynLoad_Error ret = OSDynLoad_IsModuleLoaded("libwkc", &libwkc); 24 | 25 | if (ret != OS_DYNLOAD_OK || libwkc == 0) { 26 | DEBUG_FUNCTION_LINE("OSDynLoad_Acquire failed to get libwkc.rpl in tvii. (Most likely not loaded). With error: %d", ret); 27 | return; 28 | } 29 | 30 | if (OSDynLoad_FindExport(libwkc, OS_DYNLOAD_EXPORT_FUNC, "WKCWebKitSSLRegisterRootCAByDER__3WKCFPCci", (void **) &WKC_SSLRegisterRootCAByDER) != OS_DYNLOAD_OK) { 31 | DEBUG_FUNCTION_LINE("FindExport setDeveloperExtrasEnabled__Q2_3WKC11WKCSettingsFb failed."); 32 | return; 33 | } 34 | 35 | void* ret1 = WKC_SSLRegisterRootCAByDER((const char *)(gts_der), gts_der_size); 36 | } 37 | }; // namespace ssl 38 | 39 | DECL_FUNCTION(NSSLError, NSSLAddServerPKI, NSSLContextHandle context, NSSLServerCertId pki) { 40 | if (config::connectToRose) { 41 | NSSLError ret = NSSLAddServerPKIExternal(context, gts_der, gts_der_size, 0); 42 | // DEBUG("Added GTS certificate to NSSL context. code: %d", ret); 43 | } 44 | 45 | return real_NSSLAddServerPKI(context, pki); 46 | } 47 | 48 | WUPS_MUST_REPLACE_FOR_PROCESS(NSSLAddServerPKI, WUPS_LOADER_LIBRARY_NSYSNET, NSSLAddServerPKI, WUPS_FP_TARGET_PROCESS_TVII); -------------------------------------------------------------------------------- /src/patches/ssl.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include "../utils/logger.h" 5 | 6 | namespace patches::ssl { 7 | void addCertificateToWebKit(); 8 | }; // namespace ssl -------------------------------------------------------------------------------- /src/patches/tviiIcon.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "../config.hpp" 16 | #include "../utils/patch.hpp" 17 | #include "../utils/logger.h" 18 | 19 | namespace patches::icon { 20 | 21 | const char root_rpx_check[] = "/vol/external01/wiiu/payload.elf"; 22 | 23 | OSDynLoad_NotifyData men_rpx; 24 | OSDynLoad_NotifyData hbm_rpx; 25 | 26 | void perform_men_patches(bool enable) { 27 | if (utils::isJapanConsole()) { 28 | DEBUG_FUNCTION_LINE("Japan console detected, skipping men patches"); 29 | return; 30 | } 31 | 32 | if (!utils::is555OrHigher()) { 33 | DEBUG_FUNCTION_LINE("Console not version 5.5.5 or greater, skipping men patches"); 34 | return; 35 | } 36 | 37 | if (!utils::patch::find_rpl(men_rpx, "men.rpx")) { 38 | DEBUG_FUNCTION_LINE("perform_men_patches: couldnt find men.rpx"); 39 | return; 40 | } 41 | 42 | if (utils::patch::find_mem(men_rpx.dataAddr, men_rpx.dataSize, root_rpx_check, sizeof(root_rpx_check))) { 43 | DEBUG_FUNCTION_LINE("perform_men_patches: men.rpx has been replaced by root.rpx, skipping patches ..."); 44 | return; 45 | } 46 | 47 | if (enable) { 48 | DEBUG_FUNCTION_LINE("perform_men_patches: enabling tvii patches"); 49 | utils::patch::patch_instruction((uint8_t *) men_rpx.textAddr + 0x1e0b10, 0x5403d97e, 50 | 0x38600001); // v277 51 | utils::patch::patch_instruction((uint8_t *) men_rpx.textAddr + 0x1e0a20, 0x5403d97e, 52 | 0x38600001); // v257 53 | } else { 54 | DEBUG_FUNCTION_LINE("perform_men_patches: disabling tvii patches"); 55 | utils::patch::patch_instruction((uint8_t *) men_rpx.textAddr + 0x1e0b10, 0x38600001, 56 | 0x5403d97e); // v277 57 | utils::patch::patch_instruction((uint8_t *) men_rpx.textAddr + 0x1e0a20, 0x38600001, 58 | 0x5403d97e); // v257 59 | } 60 | } 61 | 62 | void perform_hbm_patches(bool enable) { 63 | WHBLogUdpInit(); 64 | WHBLogCafeInit(); 65 | WHBLogModuleInit(); 66 | 67 | if (utils::isJapanConsole()) { 68 | DEBUG_FUNCTION_LINE("Japan console detected, skipping hbm patches"); 69 | return; 70 | } 71 | 72 | if (!utils::is555OrHigher()) { 73 | DEBUG_FUNCTION_LINE("Console not version 5.5.5 or greater, skipping hbm patches"); 74 | return; 75 | } 76 | 77 | if (!utils::patch::find_rpl(hbm_rpx, "hbm.rpx")) { 78 | DEBUG_FUNCTION_LINE("perform_hbm_patches: couldnt find hbm.rpx"); 79 | return; 80 | } 81 | 82 | if (enable) { 83 | DEBUG_FUNCTION_LINE("perform_hbm_patches: enabling tvii patches"); 84 | utils::patch::patch_instruction((uint8_t *) hbm_rpx.textAddr + 0x0ec430, 0x5403d97e, 85 | 0x38600001); // v197 86 | utils::patch::patch_instruction((uint8_t *) hbm_rpx.textAddr + 0x0ec434, 0x7c606110, 87 | 0x38600001); // v180 88 | } else { 89 | DEBUG_FUNCTION_LINE("perform_hbm_patches: disabling tvii patches"); 90 | utils::patch::patch_instruction((uint8_t *) hbm_rpx.textAddr + 0x0ec430, 0x38600001, 91 | 0x5403d97e); // v197 92 | utils::patch::patch_instruction((uint8_t *) hbm_rpx.textAddr + 0x0ec434, 0x38600001, 93 | 0x7c606110); // v180 94 | } 95 | } 96 | }; // namespace icon 97 | 98 | DECL_FUNCTION(int, FSOpenFile_TVII, FSClient *pClient, FSCmdBlock *pCmd, const char *path, const char *mode, int *handle, int error) { 99 | if (strcmp("/vol/content/Common/Package/Hbm2-2.pack", path) == 0) { 100 | patches::icon::perform_hbm_patches(config::tviiIconHBM); 101 | } 102 | 103 | return real_FSOpenFile_TVII(pClient, pCmd, path, mode, handle, error);; 104 | } 105 | 106 | WUPS_MUST_REPLACE_FOR_PROCESS(FSOpenFile_TVII, WUPS_LOADER_LIBRARY_COREINIT, FSOpenFile, WUPS_FP_TARGET_PROCESS_ALL); -------------------------------------------------------------------------------- /src/patches/tviiIcon.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../utils/patch.hpp" 10 | 11 | namespace patches::icon { 12 | extern const char root_rpx_check[]; 13 | 14 | void perform_men_patches(bool enable); 15 | 16 | void perform_hbm_patches(bool enable); 17 | }; // namespace icon -------------------------------------------------------------------------------- /src/utils/Notification.cpp: -------------------------------------------------------------------------------- 1 | /* Copyright 2024 Pretendo Network contributors 2 | 3 | This program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with this program. If not, see . 15 | */ 16 | 17 | #include "Notification.hpp" 18 | #include 19 | #include 20 | 21 | void ShowNotification(const char *notification) { 22 | auto err1 = NotificationModule_SetDefaultValue( 23 | NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, 24 | NOTIFICATION_MODULE_DEFAULT_OPTION_KEEP_UNTIL_SHOWN, true); 25 | auto err2 = NotificationModule_SetDefaultValue( 26 | NOTIFICATION_MODULE_NOTIFICATION_TYPE_INFO, 27 | NOTIFICATION_MODULE_DEFAULT_OPTION_DURATION_BEFORE_FADE_OUT, 15.0f); 28 | 29 | if (err1 != NOTIFICATION_MODULE_RESULT_SUCCESS || 30 | err2 != NOTIFICATION_MODULE_RESULT_SUCCESS) 31 | return; 32 | 33 | NotificationModule_AddInfoNotification(notification); 34 | } 35 | -------------------------------------------------------------------------------- /src/utils/Notification.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void ShowNotification(const char *notification); 4 | -------------------------------------------------------------------------------- /src/utils/logger.h: -------------------------------------------------------------------------------- 1 | // Taken from the Inkay plugin by Pretendo Network. Original code credit goes to Pretendo. 2 | // Edited by Cooper (@coopeeo) 3 | 4 | #pragma once 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) 13 | #define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) 14 | 15 | #define OSFATAL_FUNCTION_LINE(FMT, ARGS...)do { \ 16 | OSFatal_printf("Rosé Patcher - OSFatal - [%s]%s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ 17 | } while (0) 18 | 19 | #define DEBUG_FUNCTION_LINE(FMT, ARGS...)do { \ 20 | WHBLogPrintf("Rosé Patcher - Debug - [%s]%s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ 21 | } while (0); 22 | 23 | #define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...)do { \ 24 | WHBLogWritef("Rosé Patcher - Debug - [%s]%s@L%04d: " FMT "",__FILENAME__,__FUNCTION__, __LINE__, ## ARGS); \ 25 | } while (0); 26 | 27 | #define DEBUG(FMT, ARGS...)do { \ 28 | WHBLogPrintf("Rosé Patcher - Debug: " FMT "", ## ARGS); \ 29 | } while (0); 30 | 31 | #define DEBUG_WRITE(FMT, ARGS...)do { \ 32 | WHBLogWritef("Rosé Patcher - Debug: " FMT "", ## ARGS); \ 33 | } while (0); 34 | -------------------------------------------------------------------------------- /src/utils/patch.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #include "logger.h" 16 | 17 | namespace utils::patch { 18 | OSDynLoad_NotifyData men_rpx; 19 | OSDynLoad_NotifyData hbm_rpx; 20 | 21 | uint32_t find_mem(uint32_t start, uint32_t size, const char *original_val, 22 | size_t original_val_sz) { 23 | for (uint32_t addr = start; addr < start + size - original_val_sz; addr++) { 24 | if (memcmp(original_val, (void *) addr, original_val_sz) == 0) { 25 | return addr; 26 | } 27 | } 28 | return 0; 29 | } 30 | 31 | bool replace_mem(uint32_t start, uint32_t size, const char *original_val, 32 | size_t original_val_sz, const char *new_val, size_t new_val_sz) { 33 | uint32_t addr = find_mem(start, size, original_val, original_val_sz); 34 | if (addr) { 35 | DEBUG_FUNCTION_LINE("replace: writing to %08X (%s) with %s", addr, 36 | original_val, new_val); 37 | KernelCopyData(OSEffectiveToPhysical(addr), 38 | OSEffectiveToPhysical((uint32_t) new_val), new_val_sz); 39 | return true; 40 | } 41 | return false; 42 | } 43 | 44 | bool patch_instruction(void *instr, uint32_t original, uint32_t replacement) { 45 | uint32_t current = *(uint32_t *) instr; 46 | 47 | if (current != original) 48 | return current == replacement; 49 | 50 | DEBUG_FUNCTION_LINE("patch_instruction: writing to %08X (%08X) with %08X", 51 | (uint32_t) instr, current, replacement); 52 | 53 | KernelCopyData(OSEffectiveToPhysical((uint32_t) instr), 54 | OSEffectiveToPhysical((uint32_t) &replacement), 55 | sizeof(replacement)); 56 | DCFlushRange(instr, 4); 57 | ICInvalidateRange(instr, 4); 58 | 59 | current = *(uint32_t *) instr; 60 | 61 | return true; 62 | } 63 | 64 | bool patch_dynload_instructions() { 65 | uint32_t *patch1 = ((uint32_t *) &OSDynLoad_GetNumberOfRPLs) + 6; 66 | uint32_t *patch2 = ((uint32_t *) &OSDynLoad_GetRPLInfo) + 22; 67 | 68 | if (!patch_instruction(patch1, 0x41820038 /* beq +38 */, 69 | 0x60000000 /* nop */)) 70 | return false; 71 | if (!patch_instruction(patch2, 0x41820100 /* beq +100 */, 72 | 0x60000000 /* nop */)) 73 | return false; 74 | 75 | return true; 76 | } 77 | 78 | bool get_rpl_info(std::vector &rpls) { 79 | int num_rpls = OSDynLoad_GetNumberOfRPLs(); 80 | 81 | DEBUG_FUNCTION_LINE("get_rpl_info: %d RPL(s) running", num_rpls); 82 | 83 | if (num_rpls == 0) { 84 | return false; 85 | } 86 | 87 | rpls.resize(num_rpls); 88 | 89 | bool ret = OSDynLoad_GetRPLInfo(0, num_rpls, rpls.data()); 90 | 91 | return ret; 92 | } 93 | 94 | bool find_rpl(OSDynLoad_NotifyData &found_rpl, const std::string &name) { 95 | if (!patch_dynload_instructions()) { 96 | DEBUG_FUNCTION_LINE("find_rpl: failed to patch dynload functions"); 97 | return false; 98 | } 99 | 100 | std::vector rpl_info; 101 | if (!get_rpl_info(rpl_info)) { 102 | DEBUG_FUNCTION_LINE("find_rpl: failed to get rpl info"); 103 | return false; 104 | } 105 | 106 | DEBUG_FUNCTION_LINE("find_rpl: got rpl info"); 107 | 108 | for (const auto &rpl : rpl_info) { 109 | if (rpl.name == nullptr || rpl.name[0] == '\0') { 110 | continue; 111 | } 112 | if (std::string_view(rpl.name).ends_with(name)) { 113 | found_rpl = rpl; 114 | DEBUG_FUNCTION_LINE("find_rpl: found rpl %s", name.c_str()); 115 | return true; 116 | } 117 | } 118 | 119 | return false; 120 | } 121 | 122 | }; // namespace patch -------------------------------------------------------------------------------- /src/utils/patch.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include "utils.hpp" 4 | #include 5 | 6 | namespace utils::patch { 7 | uint32_t find_mem(uint32_t start, uint32_t size, const char *original_val, size_t original_val_sz); 8 | bool replace_mem(uint32_t start, uint32_t size, const char *original_val, size_t original_val_sz, const char *new_val, size_t new_val_sz); 9 | 10 | bool patch_instruction(void *instr, uint32_t original, uint32_t replacement); 11 | bool patch_dynload_instructions(); 12 | 13 | bool get_rpl_info(std::vector &rpls); 14 | bool find_rpl(OSDynLoad_NotifyData &found_rpl, const std::string &name); 15 | }; // namespace patch -------------------------------------------------------------------------------- /src/utils/utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | #include "utils.hpp" 11 | #include "../config.hpp" 12 | 13 | #define VINO_TITLE_ID_JP 0x000500301001300A 14 | #define VINO_CLIENT_ID_JP "547e315c1966905040e2d48dff24439a" 15 | 16 | #define VINO_TITLE_ID_US 0x000500301001310A 17 | #define VINO_CLIENT_ID_US "87a44dad436407e4ec47ad42ed68bf8c" 18 | 19 | #define VINO_TITLE_ID_EU 0x000500301001320A 20 | #define VINO_CLIENT_ID_EU "8bc9387d0797e003c3210acfae01e109" 21 | 22 | #define WII_U_MENU_TITLE_ID_JP 0x5001010040000 23 | #define WII_U_MENU_TITLE_ID_US 0x5001010040100 24 | #define WII_U_MENU_TITLE_ID_EU 0x5001010040200 25 | 26 | namespace utils { 27 | MCPSystemVersion version = { .major = 0, .minor = 0, .patch = 0, .region = 'N' }; 28 | 29 | bool isVinoClientID(const char *client_id) { 30 | return strcmp(client_id, VINO_CLIENT_ID_JP) == 0 || 31 | strcmp(client_id, VINO_CLIENT_ID_US) == 0 || 32 | strcmp(client_id, VINO_CLIENT_ID_EU) == 0; 33 | } 34 | 35 | bool isVinoTitleID(uint32_t title_id) { 36 | return title_id == VINO_TITLE_ID_JP || 37 | title_id == VINO_TITLE_ID_US || 38 | title_id == VINO_TITLE_ID_EU; 39 | } 40 | 41 | bool isWiiUMenuTitleID(uint32_t title_id, bool includeJPN) { 42 | return (title_id == WII_U_MENU_TITLE_ID_JP && includeJPN) || 43 | title_id == WII_U_MENU_TITLE_ID_US || 44 | title_id == WII_U_MENU_TITLE_ID_EU; 45 | } 46 | 47 | MCPSystemVersion getSystemVersion() { 48 | if (version.major != 0 && version.minor != 0 && version.patch != 0 && version.region != 'N') { 49 | return version; 50 | } 51 | int mcp = MCP_Open(); 52 | int ret = MCP_GetSystemVersion(mcp, &version); 53 | if (ret < 0) { 54 | version = { .major = 0, .minor = 0, .patch = 0, .region = 'N' }; 55 | } 56 | MCP_Close(mcp); 57 | return version; 58 | } 59 | 60 | char getConsoleRegion() { 61 | return getSystemVersion().region; 62 | } 63 | 64 | bool isJapanConsole() { 65 | return getConsoleRegion() == 'J' || config::forceJPNconsole; 66 | } 67 | 68 | bool isUSAConsole() { 69 | return getConsoleRegion() == 'U'; 70 | } 71 | 72 | bool isEuropeConsole() { 73 | return getConsoleRegion() == 'E'; 74 | } 75 | 76 | bool is555OrHigher() { 77 | return getSystemVersion().major == 5 && getSystemVersion().minor == 5 && getSystemVersion().patch >= 5 && (getSystemVersion().region == 'U' || getSystemVersion().region == 'E' || getSystemVersion().region == 'J'); 78 | } 79 | }; // namespace utils -------------------------------------------------------------------------------- /src/utils/utils.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | namespace utils { 12 | bool isVinoClientID(const char *client_id); 13 | bool isVinoTitleID(uint32_t title_id); 14 | 15 | bool isWiiUMenuTitleID(uint32_t title_id, bool includeJPN = true); 16 | 17 | MCPSystemVersion getSystemVersion(); 18 | 19 | char getConsoleRegion(); 20 | bool isJapanConsole(); 21 | bool isUSAConsole(); 22 | bool isEuropeConsole(); 23 | 24 | bool is555OrHigher(); 25 | }; // namespace utils --------------------------------------------------------------------------------