mirror of
https://github.com/PretendoNetwork/rce_patches.git
synced 2025-04-02 11:02:12 -04:00
Simplify patches by using the latest libfunctionpatcher, add a config menu, make logging optional, always log blocked attacks.
This commit is contained in:
parent
8743a2e061
commit
cf9620d7d3
15 changed files with 465 additions and 301 deletions
14
Makefile
14
Makefile
|
@ -21,7 +21,7 @@ WUMS_ROOT := $(DEVKITPRO)/wums
|
|||
#-------------------------------------------------------------------------------
|
||||
TARGET := rce_patches
|
||||
BUILD := build
|
||||
SOURCES := source source/patcher
|
||||
SOURCES := source source/utils
|
||||
DATA := data
|
||||
INCLUDES := source
|
||||
|
||||
|
@ -36,7 +36,17 @@ CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ -D__WUPS__
|
|||
CXXFLAGS := $(CFLAGS) -std=gnu++20
|
||||
|
||||
ASFLAGS := $(ARCH)
|
||||
LDFLAGS = $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) -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
|
||||
|
||||
|
|
30
README.md
30
README.md
|
@ -8,3 +8,33 @@
|
|||
- Splatoon (All regions, v272)
|
||||
- [ENLBufferPwn](https://github.com/PabloMK7/ENLBufferPwn) fix
|
||||
- ENL nullptr deref fix + OOB read
|
||||
|
||||
## Buildflags
|
||||
|
||||
### Logging
|
||||
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 the Dockerfile
|
||||
|
||||
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
|
||||
```
|
||||
|
||||
## Format the code via docker
|
||||
|
||||
`docker run --rm -v ${PWD}:/src wiiuenv/clang-format:13.0.0-2 -r ./source -i`
|
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;
|
107
source/main.cpp
107
source/main.cpp
|
@ -1,56 +1,87 @@
|
|||
#include <string.h>
|
||||
#include <wups.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "globals.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_DESCRIPTION("Patches security issues in WiiU games that could be triggered remotely");
|
||||
WUPS_PLUGIN_VERSION("v1.0");
|
||||
WUPS_PLUGIN_AUTHOR("Rambo6Glaz");
|
||||
WUPS_PLUGIN_AUTHOR("Rambo6Glaz, Maschell");
|
||||
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;
|
||||
|
||||
void RemovePatches(std::vector<PatchData> &patchHandles) {
|
||||
for (auto &patch : patchHandles) {
|
||||
if (FunctionPatcher_RemoveFunctionPatch(patch.handle) != FUNCTION_PATCHER_RESULT_SUCCESS) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Failed to remove function patch %08X", patch.handle);
|
||||
}
|
||||
}
|
||||
patchHandles.clear();
|
||||
}
|
||||
|
||||
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 this is not a supported title, no need to do anything
|
||||
uint64_t titleId = OSGetTitleID();
|
||||
GamePatches *gamePatch = nullptr;
|
||||
for (auto &patch : sGamePatchList) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (patch.mRegionalTIDs[i] == titleId) {
|
||||
gamePatch = &patch;
|
||||
break;
|
||||
}
|
||||
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 patches");
|
||||
RemovePatches(mk8Patches);
|
||||
}
|
||||
}
|
||||
|
||||
if (!gamePatch)
|
||||
return;
|
||||
|
||||
// Init logging
|
||||
if (!WHBLogModuleInit()) {
|
||||
WHBLogCafeInit();
|
||||
WHBLogUdpInit();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
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("Splatoon: Function %s (handle: %08X) has NOT been patched", patch.name.c_str(), patch.handle);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
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 <coreinit/memorymap.h>
|
||||
#include <kernel/kernel.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,71 +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,32 +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 <algorithm>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#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,10 +1,13 @@
|
|||
#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);
|
||||
}
|
||||
|
@ -12,9 +15,11 @@ DECL_FUNCTION(bool, enl_ParseIdentificationToken, void *identifiationInfo, sead_
|
|||
return real_enl_ParseIdentificationToken(identifiationInfo, identificationToken);
|
||||
}
|
||||
|
||||
enl_ContentTransporter *(*real_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) {
|
||||
DECL_FUNCTION(enl_ContentTransporter *, enl_TransportManager_getContentTransporter, void *_this, unsigned char &id) {
|
||||
return real_enl_TransportManager_getContentTransporter(_this, id);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(void, enl_TransportManager_updateReceiveBuffer_, void *_this, signed char const &bufferId, uint8_t *data, uint32_t size) {
|
||||
// Check for end record in the data, if there is not, drop packet
|
||||
bool hasEndRecord = false;
|
||||
|
||||
|
@ -29,107 +34,134 @@ DECL_FUNCTION(void, enl_TransportManager_updateReceiveBuffer_, void *_this, sign
|
|||
|
||||
enl_ContentTransporter *contentTransp = real_enl_TransportManager_getContentTransporter(_this, record->mContentTransporterID);
|
||||
// Actual fix for the ENL nullptr deref crash (lmao)
|
||||
if (!contentTransp)
|
||||
if (!contentTransp) {
|
||||
DEBUG_FUNCTION_LINE_INFO("Avoided ENL nullptr deref crash in enl_TransportManager_updateReceiveBuffer_!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (record->mContentLength > 0x440)
|
||||
if (record->mContentLength > 0x440) {
|
||||
DEBUG_FUNCTION_LINE_INFO("record->mContentLength was over 0x440 in enl_TransportManager_updateReceiveBuffer_!");
|
||||
return;
|
||||
}
|
||||
|
||||
pData += sizeof(enl_RecordHeader);
|
||||
pData += record->mContentLength;
|
||||
}
|
||||
|
||||
if (!hasEndRecord)
|
||||
if (!hasEndRecord) {
|
||||
return;
|
||||
}
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
// ==========================================================================================
|
||||
|
||||
void MARIO_KART_8_ApplyPatch(EPatchType type) {
|
||||
auto turbo_rpx = FindRPL(*gRPLInfo, "Turbo.rpx");
|
||||
if (!turbo_rpx) {
|
||||
WHBLogPrintf("rce_patches: Couldn't find Turbo.rpx ...");
|
||||
return;
|
||||
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);
|
||||
|
||||
if (type == PATCH_ENL_ID_TOKEN_RCE) {
|
||||
// Address of 'enl::PiaUtil::ParseIdentificationToken'
|
||||
uint32_t addr_func = turbo_rpx->textAddr + 0x8E3930;
|
||||
function_replacement_data_t repl = REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(
|
||||
enl_ParseIdentificationToken,
|
||||
OSEffectiveToPhysical(addr_func),
|
||||
addr_func,
|
||||
FP_TARGET_PROCESS_GAME_AND_MENU);
|
||||
FunctionPatcherPatchFunction(&repl, nullptr);
|
||||
|
||||
WHBLogPrintf("rce_patches: Patched Mario Kart 8 (PATCH_ENL_ID_TOKEN_RCE)");
|
||||
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);
|
||||
|
||||
if (type == PATCH_ENL_BUFFER_RCE) {
|
||||
real_enl_TransportManager_getContentTransporter = (enl_ContentTransporter * (*) (void *, unsigned char &) )(turbo_rpx->textAddr + 0x8D7678);
|
||||
|
||||
// Address of 'enl::TransportManager::updateReceiveBuffer_'
|
||||
uint32_t addr_func = turbo_rpx->textAddr + 0x8D772C;
|
||||
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);
|
||||
|
||||
addr_func = turbo_rpx->textAddr + 0x8CF228;
|
||||
repl = REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(
|
||||
enl_Buffer_set,
|
||||
OSEffectiveToPhysical(addr_func),
|
||||
addr_func,
|
||||
FP_TARGET_PROCESS_GAME_AND_MENU);
|
||||
FunctionPatcherPatchFunction(&repl, nullptr);
|
||||
|
||||
WHBLogPrintf("rce_patches: Patched Mario Kart 8 (PATCH_ENL_BUFFER_RCE)");
|
||||
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);
|
||||
|
||||
WHBLogPrintf("rce_patches: Patched Mario Kart 8 (PATCH_ENL_BUFFER_RCE)");
|
||||
return true;
|
||||
}
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
void SPLATOON_ApplyPatch(EPatchType type) {
|
||||
|
||||
auto gambit_rpx = FindRPL(*gRPLInfo, "Gambit.rpx");
|
||||
if (!gambit_rpx) {
|
||||
WHBLogPrintf("rce_patches: Couldn't find Gambit.rpx ...");
|
||||
return;
|
||||
bool SPLATOON_AddPatches(std::vector<PatchData> &functionPatches) {
|
||||
uint64_t titleIds[] = {SPLATOON_TID};
|
||||
function_replacement_data_t repl = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||
enl_TransportManager_getContentTransporter,
|
||||
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||
"Gambit.rpx",
|
||||
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::PiaUtil::ParseIdentificationToken", handle);
|
||||
|
||||
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);
|
||||
|
||||
// Address of 'enl:Buffer::set'
|
||||
addr_func = gambit_rpx->textAddr + 0xB4D178;
|
||||
repl = REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(
|
||||
enl_Buffer_set,
|
||||
OSEffectiveToPhysical(addr_func),
|
||||
addr_func,
|
||||
FP_TARGET_PROCESS_GAME_AND_MENU);
|
||||
FunctionPatcherPatchFunction(&repl, nullptr);
|
||||
|
||||
WHBLogPrintf("rce_patches: Patched Splatoon (PATCH_ENL_BUFFER_RCE)");
|
||||
function_replacement_data_t repl1 = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||
enl_TransportManager_updateReceiveBuffer_,
|
||||
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||
"Gambit.rpx",
|
||||
0xB41140, // Address of 'enl::TransportManager::updateReceiveBuffer_'
|
||||
272, 272);
|
||||
if (FunctionPatcher_AddFunctionPatch(&repl1, &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 repl2 = REPLACE_FUNCTION_OF_EXECUTABLE_BY_ADDRESS_WITH_VERSION(
|
||||
enl_Buffer_set,
|
||||
titleIds, sizeof(titleIds) / sizeof(titleIds[0]),
|
||||
"Gambit.rpx",
|
||||
0xB4D178, // Address of 'enl:Buffer::set'
|
||||
272, 272);
|
||||
if (FunctionPatcher_AddFunctionPatch(&repl2, &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;
|
||||
}
|
|
@ -1,48 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
|
||||
#include <whb/log.h>
|
||||
#include <whb/log_cafe.h>
|
||||
#include <whb/log_module.h>
|
||||
#include <whb/log_udp.h>
|
||||
|
||||
#include <coreinit/title.h>
|
||||
|
||||
#include <patcher/patcher.h>
|
||||
#include <patcher/rplinfo.h>
|
||||
|
||||
#include <kernel/kernel.h>
|
||||
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/memorymap.h>
|
||||
|
||||
#undef DECL_FUNCTION
|
||||
#include <function_patcher/function_patching.h>
|
||||
|
||||
enum EPatchType {
|
||||
PATCH_ENL_BUFFER_RCE,
|
||||
PATCH_ENL_ID_TOKEN_RCE,
|
||||
};
|
||||
|
||||
struct GamePatches {
|
||||
const char *mTitleName;
|
||||
uint64_t mRegionalTIDs[3];
|
||||
std::vector<EPatchType> mPatchTypes;
|
||||
void (*mPatchFunc)(EPatchType type);
|
||||
};
|
||||
#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>
|
||||
|
||||
struct sead_String {
|
||||
char *mBuffer;
|
||||
uint32_t vtable;
|
||||
};
|
||||
WUT_CHECK_OFFSET(sead_String, 0x00, mBuffer);
|
||||
WUT_CHECK_OFFSET(sead_String, 0x04, vtable);
|
||||
|
||||
struct __attribute__((__packed__)) enl_RecordHeader {
|
||||
uint8_t mContentTransporterID;
|
||||
uint16_t mContentLength;
|
||||
};
|
||||
WUT_CHECK_OFFSET(enl_RecordHeader, 0x00, mContentTransporterID);
|
||||
WUT_CHECK_OFFSET(enl_RecordHeader, 0x01, mContentLength);
|
||||
|
||||
struct enl_Buffer {
|
||||
uint8_t *mData;
|
||||
|
@ -50,6 +32,10 @@ struct enl_Buffer {
|
|||
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 enl_ContentTransporter {
|
||||
struct ContentTransporterVtbl {
|
||||
|
@ -67,19 +53,41 @@ struct enl_ContentTransporter {
|
|||
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);
|
||||
|
||||
|
||||
class PatchData {
|
||||
public:
|
||||
PatchData(std::string name, PatchedFunctionHandle handle) : name(std::move(name)), handle(handle) {
|
||||
}
|
||||
|
||||
std::string name;
|
||||
PatchedFunctionHandle handle;
|
||||
};
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
#define MARIO_KART_8_TID_J 0x000500001010EB00
|
||||
#define MARIO_KART_8_TID_U 0x000500001010EC00
|
||||
#define MARIO_KART_8_TID_E 0x000500001010ED00
|
||||
#define MARIO_KART_8_TID_J 0x000500001010EB00
|
||||
#define MARIO_KART_8_TID_U 0x000500001010EC00
|
||||
#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_PATCHES PATCH_ENL_BUFFER_RCE, PATCH_ENL_ID_TOKEN_RCE
|
||||
#define MARIO_KART_8_TID MARIO_KART_8_TID_J, MARIO_KART_8_TID_U, MARIO_KART_8_TID_E
|
||||
|
||||
void MARIO_KART_8_ApplyPatch(EPatchType type);
|
||||
bool MARIO_KART_8_AddPatches(std::vector<PatchData> &functionPatches);
|
||||
|
||||
// ==========================================================================================
|
||||
|
||||
|
@ -90,12 +98,6 @@ void MARIO_KART_8_ApplyPatch(EPatchType type);
|
|||
#define SPLATOON_TID SPLATOON_TID_J, SPLATOON_TID_U, SPLATOON_TID_E
|
||||
#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
|
||||
|
||||
#include <coreinit/debug.h>
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
#include <whb/log.h>
|
||||
#define LOG_APP_TYPE "P"
|
||||
#define LOG_APP_NAME "rce_patches"
|
||||
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
|
||||
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__)
|
||||
|
||||
#define OSFATAL_FUNCTION_LINE(FMT, ARGS...) \
|
||||
do { \
|
||||
OSFatal_printf("[%s]%s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", FMT, ##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)
|
||||
|
||||
#define DEBUG_FUNCTION_LINE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogPrintf("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0);
|
||||
#ifdef DEBUG
|
||||
|
||||
#define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) \
|
||||
do { \
|
||||
WHBLogWritef("[%23s]%30s@L%04d: " FMT "", __FILENAME__, __FUNCTION__, __LINE__, ##ARGS); \
|
||||
} while (0);
|
||||
#ifdef VERBOSE_DEBUG
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE(FMT, ARGS...) LOG(WHBLogPrintf, FMT, ##ARGS)
|
||||
#define DEBUG_FUNCTION_LINE_VERBOSE_EX(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "", "", FMT, ##ARGS);
|
||||
#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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue