Update and commit missing files

This commit is contained in:
BullyWiiPlaza 2017-06-03 16:02:59 +02:00
parent d06770063c
commit 19b8e017ef
26 changed files with 767 additions and 103 deletions

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="MarkdownExportedFiles">
<htmlFiles />
<imageFiles />
<otherFiles />
</component>
</project>

View File

@ -1,13 +1,18 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<app version="1">
<name>TCPgecko</name> <app>
<coder>wj44, BullyWiiPlaza</coder> <name>TCP Gecko</name>
<version>2.2</version> <coder>BullyWiiPlaza, wj44, dimok, Chadderz, Marionumber1</coder>
<version>2.3</version>
<short_description>WiiU RAM Hacking</short_description> <short_description>WiiU RAM Hacking</short_description>
<long_description>A memory editor that does magical things to your games. In order to apply Cafe Codes (real-time cheats) use JGecko U. <long_description>A memory editor that does magical things to your games. In order to develop and apply real-time
Special Thanks to: cheats use JGecko U.
Chadderz, Marionumber1 - TCPGecko codehandler
pwsincd - icon and xml Special thanks to:
CosmoCortney - codehandler for cheat codes, xml Chadderz, Marionumber1 - Original TCP Gecko Installer
</long_description> dimok - Homebrew Launcher
kinnay - Diibugger
pwsincd - Icon and XML
CosmoCortney - Cheat code handler
</long_description>
</app> </app>

16
src/address.c Normal file
View File

@ -0,0 +1,16 @@
#include "address.h"
#include "dynamic_libs/os_functions.h"
int validateAddressRange(int starting_address, int ending_address) {
return __OSValidateAddressSpaceRange(1, (void *) starting_address, ending_address - starting_address + 1);
}
bool isValidDataAddress(int address) {
return OSIsAddressValid((const void *) address)
&& address >= 0x10000000
&& address < 0x50000000;
}
int roundUpToAligned(int number) {
return (number + 3) & ~0x03;
}

12
src/address.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef TCPGECKO_ADDRESS_H
#define TCPGECKO_ADDRESS_H
#include <stdbool.h>
int validateAddressRange(int starting_address, int ending_address);
bool isValidDataAddress(int address);
int roundUpToAligned(int number);
#endif

53
src/assertions.h Normal file
View File

@ -0,0 +1,53 @@
#ifndef TCPGECKO_ASSERTIONS_H
#define TCPGECKO_ASSERTIONS_H
#define ASSERT_MINIMUM_HOLDS(actual, minimum, variableName) \
if(actual < minimum) { \
char buffer[100] = {0}; \
__os_snprintf(buffer, 100, "%s: Limit exceeded (minimum: %i, actual: %i)", variableName, minimum, actual); \
OSFatal(buffer); \
} \
#define ASSERT_MAXIMUM_HOLDS(maximum, actual, variableName) \
if(actual > maximum) { \
char buffer[100] = {0}; \
__os_snprintf(buffer, 100, "%s: Limit exceeded (maximum: %i, actual: %i)", variableName, maximum, actual); \
OSFatal(buffer); \
} \
#define ASSERT_FUNCTION_SUCCEEDED(returnValue, functionName) \
if (returnValue < 0) { \
char buffer[100] = {0}; \
__os_snprintf(buffer, 100, "%s failed with return value: %i", functionName, returnValue); \
OSFatal(buffer); \
} \
#define ASSERT_VALID_EFFECTIVE_ADDRESS(effectiveAddress, message) \
if(!OSIsAddressValid((void *) effectiveAddress)) { \
char buffer[100] = {0}; \
__os_snprintf(buffer, 100, "Address %04x invalid: %s", effectiveAddress, message); \
OSFatal(buffer); \
}
#define ASSERT_INTEGER(actual, expected, name) \
if(actual != expected) { \
char buffer[50] = {0}; \
__os_snprintf(buffer, 50, "%s assertion failed: %i == %i", name, actual, expected); \
OSFatal(buffer); \
}
#define ASSERT_STRING(actual, expected) \
if(strcmp(actual, expected) != 0) { \
char buffer[50] = {0}; \
__os_snprintf(buffer, 50, "String assertion failed: \"%s\" == \"%s\"", actual, expected); \
OSFatal(buffer); \
}
#define ASSERT_ALLOCATED(variable, name) \
if(variable == 0) { \
char buffer[50] = {0}; \
__os_snprintf(buffer, 50, "%s allocation failed", name); \
OSFatal(buffer); \
}
#endif

37
src/disassembler.c Normal file
View File

@ -0,0 +1,37 @@
#include "disassembler.h"
#include "assertions.h"
#include "dynamic_libs/os_functions.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
char *disassemblerBuffer;
void *disassemblerBufferPointer;
#define DISASSEMBLER_BUFFER_SIZE 0x1024
void formatDisassembled(char *format, ...) {
if (!disassemblerBuffer) {
disassemblerBuffer = malloc(DISASSEMBLER_BUFFER_SIZE);
ASSERT_ALLOCATED(disassemblerBuffer, "Disassembler buffer")
disassemblerBufferPointer = disassemblerBuffer;
}
va_list variableArguments;
va_start(variableArguments, format);
char *temporaryBuffer;
int printedBytesCount = vasprintf(&temporaryBuffer, format, variableArguments);
ASSERT_ALLOCATED(temporaryBuffer, "Temporary buffer")
ASSERT_MINIMUM_HOLDS(printedBytesCount, 1, "Printed bytes count")
va_end(variableArguments);
// Do not smash the buffer
long projectedSize = (void *) disassemblerBuffer - disassemblerBufferPointer + printedBytesCount;
if (projectedSize < DISASSEMBLER_BUFFER_SIZE) {
memcpy(disassemblerBuffer, temporaryBuffer, printedBytesCount);
disassemblerBuffer += printedBytesCount;
}
free(temporaryBuffer);
}

6
src/disassembler.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef TCPGECKO_DISASSEMBLER_H
#define TCPGECKO_DISASSEMBLER_H
void formatDisassembled(char *format, ...);
#endif

View File

@ -2,7 +2,7 @@
#include "dynamic_libs/gx2_functions.h" #include "dynamic_libs/gx2_functions.h"
#include "dynamic_libs/socket_functions.h" #include "dynamic_libs/socket_functions.h"
#include "common/common.h" #include "common/common.h"
#include "pygecko.h" #include "tcp_gecko.h"
#include "main.h" #include "main.h"
#include "utils/logger.h" #include "utils/logger.h"
#include "title.h" #include "title.h"

113
src/kernel.h Normal file
View File

@ -0,0 +1,113 @@
#pragma once
#include "kernel/syscalls.h"
#include "assertions.h"
#include "dynamic_libs/os_functions.h"
#include "tcp_gecko.h"
#include "utils/logger.h"
unsigned char *kernelCopyBuffer[sizeof(int)];
// TODO Variable size, not hard-coded
unsigned char *kernelCopyBufferOld[DATA_BUFFER_SIZE];
void kernelCopyData(unsigned char *destinationBuffer, unsigned char *sourceBuffer, unsigned int length) {
if (length > DATA_BUFFER_SIZE) {
OSFatal("Kernel copy buffer size exceeded");
}
memcpy(kernelCopyBufferOld, sourceBuffer, length);
SC0x25_KernelCopyData((unsigned int) OSEffectiveToPhysical(destinationBuffer), (unsigned int) &kernelCopyBufferOld, length);
DCFlushRange(destinationBuffer, (u32) length);
}
void kernelCopyInt(unsigned char *destinationBuffer, unsigned char *sourceBuffer, unsigned int length) {
memcpy(kernelCopyBuffer, sourceBuffer, length);
unsigned int destinationAddress = (unsigned int) OSEffectiveToPhysical(destinationBuffer);
SC0x25_KernelCopyData(destinationAddress, (unsigned int) &kernelCopyBuffer, length);
DCFlushRange(destinationBuffer, (u32) length);
}
void writeKernelMemory(const void *address, uint32_t value) {
((int *) kernelCopyBuffer)[0] = value;
kernelCopyInt((unsigned char *) address, (unsigned char *) kernelCopyBuffer, sizeof(int));
}
int readKernelMemory(const void *address) {
// For addresses in that range use Chadderz' function to avoid crashing
if (address > (const void *) 0xF0000000) {
log_print("Using Chadderz' kern_read()...\n");
return kern_read(address);
}
log_print("Using dimok's kernelCopy()...\n");
unsigned char *readBuffer[sizeof(int)];
kernelCopyInt((unsigned char *) readBuffer, (unsigned char *) address, sizeof(int));
return ((int *) readBuffer)[0];
}
#define KERNEL_COPY_SOURCE_ADDRESS 0x10100000
int kernelCopyService(int argc, void *argv) {
while (true) {
// Read the destination address from the source address
int destinationAddress = *(int *) KERNEL_COPY_SOURCE_ADDRESS;
// Avoid crashing
if (OSIsAddressValid((const void *) destinationAddress)) {
// Perform memory copy
unsigned char *valueBuffer = (unsigned char *) (KERNEL_COPY_SOURCE_ADDRESS + 4);
kernelCopyInt((unsigned char *) destinationAddress, valueBuffer, 4);
// "Consume" address and value for synchronization with the code handler for instance
*(int *) KERNEL_COPY_SOURCE_ADDRESS = 0;
*(((int *) KERNEL_COPY_SOURCE_ADDRESS) + 1) = 0;
}
}
}
void startKernelCopyService() {
unsigned int stack = (unsigned int) memalign(0x40, 0x100);
ASSERT_ALLOCATED(stack, "Kernel copy thread stack")
stack += 0x100;
void *thread = memalign(0x40, 0x1000);
ASSERT_ALLOCATED(thread, "Kernel copy thread")
int status = OSCreateThread(thread, kernelCopyService, 1, NULL, (u32) stack + sizeof(stack), sizeof(stack), 31,
OS_THREAD_ATTR_AFFINITY_CORE1 | OS_THREAD_ATTR_PINNED_AFFINITY | OS_THREAD_ATTR_DETACH);
ASSERT_INTEGER(status, 1, "Creating kernel copy thread")
// OSSetThreadName(thread, "Kernel Copier");
OSResumeThread(thread);
}
#define MINIMUM_KERNEL_COMPARE_LENGTH 4
#define KERNEL_MEMORY_COMPARE_STEP_SIZE 1
int kernelMemoryCompare(const void *sourceBuffer,
const void *destinationBuffer,
int length) {
if (length < MINIMUM_KERNEL_COMPARE_LENGTH) {
ASSERT_MINIMUM_HOLDS(length, MINIMUM_KERNEL_COMPARE_LENGTH, "length");
}
bool loopEntered = false;
while (kern_read(sourceBuffer) == kern_read(destinationBuffer)) {
loopEntered = true;
sourceBuffer = (char *) sourceBuffer + KERNEL_MEMORY_COMPARE_STEP_SIZE;
destinationBuffer = (char *) destinationBuffer + KERNEL_MEMORY_COMPARE_STEP_SIZE;
length -= KERNEL_MEMORY_COMPARE_STEP_SIZE;
if (length <= MINIMUM_KERNEL_COMPARE_LENGTH - 1) {
break;
}
}
if (loopEntered) {
sourceBuffer -= KERNEL_MEMORY_COMPARE_STEP_SIZE;
destinationBuffer -= KERNEL_MEMORY_COMPARE_STEP_SIZE;
}
return kern_read(sourceBuffer) - kern_read(destinationBuffer);
}

View File

@ -1,9 +1,6 @@
#include <string.h> #include <string.h>
#include "common/common.h" #include "../common/kernel_defs.h"
#include "common/kernel_defs.h" #include "../kernel/kernel_functions.h"
#include "kernel/kernel_functions.h"
#include "kernel/syscalls.h"
#include "pygecko.h"
/* our retain data */ /* our retain data */
ReducedCosAppXmlInfo cosAppXmlInfoStruct; ReducedCosAppXmlInfo cosAppXmlInfoStruct;

View File

@ -44,10 +44,6 @@ int Menu_Main(void) {
InitVPadFunctionPointers(); InitVPadFunctionPointers();
InitSysFunctionPointers(); InitSysFunctionPointers();
log_init(COMPUTER_IP_ADDRESS);
log_print("Patching functions\n");
applyFunctionPatches();
if (strcasecmp("men.rpx", cosAppXmlInfoStruct.rpx_name) == 0) { if (strcasecmp("men.rpx", cosAppXmlInfoStruct.rpx_name) == 0) {
return EXIT_RELAUNCH_ON_LOAD; return EXIT_RELAUNCH_ON_LOAD;
} else if (strlen(cosAppXmlInfoStruct.rpx_name) > 0 && } else if (strlen(cosAppXmlInfoStruct.rpx_name) > 0 &&
@ -141,15 +137,20 @@ int Menu_Main(void) {
break; break;
} }
// A Button // A Button pressed
if (pressedButtons & VPAD_BUTTON_A) { if (pressedButtons & VPAD_BUTTON_A) {
unsigned int physicalCodeHandlerAddress = (unsigned int) OSEffectiveToPhysical( unsigned int physicalCodeHandlerAddress = (unsigned int) OSEffectiveToPhysical(
(void *) CODE_HANDLER_INSTALL_ADDRESS); (void *) CODE_HANDLER_INSTALL_ADDRESS);
SC0x25_KernelCopyData((u32) physicalCodeHandlerAddress, (int) codeHandler, codeHandlerLength); SC0x25_KernelCopyData((u32) physicalCodeHandlerAddress, (unsigned int) codeHandler, codeHandlerLength);
DCFlushRange((const void *) CODE_HANDLER_INSTALL_ADDRESS, (u32) codeHandlerLength); DCFlushRange((const void *) CODE_HANDLER_INSTALL_ADDRESS, (u32) codeHandlerLength);
isCodeHandlerInstalled = true; isCodeHandlerInstalled = true;
launchMethod = TCP_GECKO; launchMethod = TCP_GECKO;
log_init(COMPUTER_IP_ADDRESS);
log_print("Patching functions\n");
applyFunctionPatches();
break; break;
} }

View File

@ -24,8 +24,7 @@
static volatile int executionCounter = 0; static volatile int executionCounter = 0;
declareFunctionHook(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, s32 declareFunctionHook(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *colorBuffer, s32 scan_target) {
scan_target) {
if (executionCounter > 120) { if (executionCounter > 120) {
GX2Surface surface = colorBuffer->surface; GX2Surface surface = colorBuffer->surface;
/*s32 format = surface.format; /*s32 format = surface.format;
@ -53,8 +52,7 @@ declareFunctionHook(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *
jpeg.img_id = 0; jpeg.img_id = 0;
}*/ }*/
log_printf("GX2CopyColorBufferToScanBuffer {surface width:%d, height:%d, image size:%d, image data:%x}\n", log_printf("GX2CopyColorBufferToScanBuffer {surface width:%d, height:%d, image size:%d, image data:%x}\n", surface.width, surface.height, surface.image_size, surface.image_data);
surface.width, surface.height, surface.image_size, surface.image_data);
executionCounter = 0; executionCounter = 0;
} }
@ -65,7 +63,7 @@ declareFunctionHook(void, GX2CopyColorBufferToScanBuffer, const GX2ColorBuffer *
} }
FunctionHook method_hooks_gx2[] __attribute__((section(".data"))) = { FunctionHook method_hooks_gx2[] __attribute__((section(".data"))) = {
makeFunctionHook(GX2CopyColorBufferToScanBuffer, LIB_GX2, STATIC_FUNCTION) // makeFunctionHook(GX2CopyColorBufferToScanBuffer, LIB_GX2, STATIC_FUNCTION)
}; };
u32 method_hooks_size_gx2 __attribute__((section(".data"))) = sizeof(method_hooks_gx2) / sizeof(FunctionHook); u32 method_hooks_size_gx2 __attribute__((section(".data"))) = sizeof(method_hooks_gx2) / sizeof(FunctionHook);

50
src/pause.h Normal file
View File

@ -0,0 +1,50 @@
#pragma once
#include "utils/logger.h"
#include "assertions.h"
#include "dynamic_libs/os_functions.h"
#include "common/fs_defs.h"
#include "kernel.h"
int (*AVMGetDRCScanMode)(int);
unsigned long getConsoleStatePatchAddress() {
if (AVMGetDRCScanMode) {
log_print("Already acquired!\n");
} else {
// Acquire the RPL and function
log_print("Acquiring...\n");
unsigned int avm_handle;
OSDynLoad_Acquire("avm.rpl", &avm_handle);
ASSERT_ALLOCATED(avm_handle, "avm.rpl")
OSDynLoad_FindExport((u32) avm_handle, 0, "AVMGetDRCScanMode", &AVMGetDRCScanMode);
ASSERT_ALLOCATED(AVMGetDRCScanMode, "AVMGetDRCScanMode")
log_print("Acquired!\n");
}
return (unsigned long) (AVMGetDRCScanMode + 0x44);
}
typedef enum {
PAUSED = 0x38000001,
RUNNING = 0x38000000
} ConsoleState;
void writeConsoleState(ConsoleState state) {
// Get the value to write
int patchValue = state;
log_printf("Patch value: %x\n", patchValue);
// Write the value
unsigned int patchAddress = getConsoleStatePatchAddress();
log_printf("Patch address: %x\n", patchAddress);
kernelCopyData((unsigned char *) patchAddress, (unsigned char *) &patchValue, 4);
}
bool isConsolePaused() {
unsigned int patchAddress = getConsoleStatePatchAddress();
log_printf("Patch address: %x\n", patchAddress);
int value = *(unsigned int *) patchAddress;
return value == PAUSED;
}

View File

@ -35,7 +35,31 @@ typedef struct OSContext {
uint32_t exception_specific0; uint32_t exception_specific0;
uint32_t exception_specific1; uint32_t exception_specific1;
/* There is actually a lot more here but we don't need the rest*/ u32 exception_type;
u32 reserved;
double fpscr;
double fpr[32];
u16 spinLockCount;
u16 state;
u32 gqr[8];
u32 pir;
double psf[32];
u64 coretime[3];
u64 starttime;
u32 error;
u32 attributes;
u32 pmc1;
u32 pmc2;
u32 pmc3;
u32 pmc4;
u32 mmcr0;
u32 mmcr1;
} OSContext; } OSContext;
#define CPU_STACK_TRACE_DEPTH 10 #define CPU_STACK_TRACE_DEPTH 10

View File

@ -0,0 +1,154 @@
#include "../utils/stringify.h"
#include "../dynamic_libs/os_functions.h"
#include "threads.h"
#include "../utils/logger.h"
#include "../main.h"
#include "utilities.h"
#include "software_breakpoints.h"
#include "../common/kernel_types.h"
#ifndef TCPGECKO_BREAKPOINTS_H
#define TCPGECKO_BREAKPOINTS_H
// Special purpose registers
#define IABR 0x3F2
#define DABR 0x3F5
// http://www.ds.ewi.tudelft.nl/vakken/in1006/instruction-set/mtspr.html
#define mtspr(spr, value) \
__asm__ __volatile__ ("mtspr %0, %1" : : "K" (spr), "r" (value)) \
// https://www.ibm.com/support/knowledgecenter/en/ssw_aix_71/com.ibm.aix.alangref/idalangref_isync_ics_instrs.htm
static inline void isync() {
__asm__ __volatile__ ("isync" : : : "memory");
}
// https://www.ibm.com/support/knowledgecenter/en/ssw_aix_61/com.ibm.aix.alangref/idalangref_eieio_instrs.htm
static inline void eieio() {
__asm__ __volatile__ ("eieio" : : : "memory");
}
// https://www.ibm.com/support/knowledgecenter/ssw_aix_71/com.ibm.aix.alangref/idalangref_rfi_retfinter_instrs.htm
static inline void rfi() {
__asm__ __volatile__ ("rfi" : : : "memory");
}
// https://www.manualslib.com/manual/606065/Ibm-Powerpc-750gx.html?page=64
static inline void setIABR(unsigned int address) {
mtspr(IABR, address);
eieio();
isync();
}
static inline int getIABRAddress() {
return mfspr(IABR);
}
static inline int getDABRAddress(void *interruptedContext) {
OSContext *context = (OSContext *) interruptedContext;
return (int) context->srr0; // Offset 0xA4
}
static inline int getIABRMatch(void *interruptedContext) {
OSContext *context = (OSContext *) interruptedContext;
return (int) context->exception_specific1; // Offset 0x98
}
unsigned char breakPointHandler(void *interruptedContext);
void registerBreakPointHandler() {
log_init(COMPUTER_IP_ADDRESS);
log_print("Registering breakpoint handler...\n");
// TODO Not working, never called?
// OSSetExceptionCallback((u8) OS_EXCEPTION_DSI, &breakPointHandler);
// OSSetExceptionCallback((u8) OS_EXCEPTION_ISI, &breakPointHandler);
// OSSetExceptionCallback((u8) OS_EXCEPTION_PROGRAM, &breakPointHandler);
OSSetExceptionCallbackEx((u8) OS_EXCEPTION_MODE_GLOBAL_ALL_CORES, (u8) OS_EXCEPTION_PROGRAM, &breakPointHandler);
// __OSSetInterruptHandler((u8) OS_EXCEPTION_PROGRAM, &breakPointHandler);
log_print("Breakpoint handler(s) registered!\n");
}
/*void forceDebuggerInitialized() {
unsigned char patchBytes[] = {0x38, 0x60, 0x00, 0x01};
patchFunction(OSIsDebuggerInitialized, (char *) patchBytes, sizeof(patchBytes), 0x1C);
}
void forceDebuggerPresent() {
unsigned char patchBytes[] = {0x38, 0x60, 0x00, 0x01, 0x60, 0x00, 0x00, 0x00};
patchFunction(OSIsDebuggerPresent, (char *) patchBytes, sizeof(patchBytes), 0x0);
}*/
static inline void setupBreakpointSupport() {
log_init(COMPUTER_IP_ADDRESS);
/*log_print("Clear and enable...\n");
__OSClearAndEnableInterrupt();
log_print("Restore...\n");
OSRestoreInterrupts();
log_print("Enable...\n");
OSEnableInterrupts();
forceDebuggerPresent();
forceDebuggerInitialized();*/
registerBreakPointHandler();
}
void setDataBreakpoint(int address, bool read, bool write) {
setupBreakpointSupport();
log_init(COMPUTER_IP_ADDRESS);
log_print("Setting DABR...\n");
OSSetDABR(1, address, read, write);
log_print("DABR set\n");
int enabled = OSIsInterruptEnabled();
log_printf("Interrupts enabled: %i\n", enabled);
}
void setInstructionBreakpoint(unsigned int address) {
setupBreakpointSupport();
// int returnedAddress;
log_print("Setting IABR #1...\n");
// OSSetIABR(1, address);
setIABR(address);
log_print("IABR set #1...\n");
/*
// TODO Causes crash
returnedAddress = getIABRAddress();
log_printf("IABR spr value: %08x\n", returnedAddress);
log_print("Setting IABR #2...\n");
setIABR(address);
log_print("IABR set #2...\n");
returnedAddress = mfspr(IABR);
log_printf("IABR spr value: %08x\n", returnedAddress);*/
}
unsigned char breakPointHandler(void *interruptedContext) {
log_init(COMPUTER_IP_ADDRESS);
// Check for data breakpoints
int dataAddress = getDABRAddress(interruptedContext);
if (OSIsAddressValid((const void *) dataAddress)) {
log_printf("Data breakpoint address: %x08\n", dataAddress);
} else {
log_printf("Data breakpoint invalid address: %x08\n", dataAddress);
// Check for instruction breakpoints
int instructionAddress = getIABRMatch(interruptedContext);
if (OSIsAddressValid((const void *) instructionAddress)) {
log_printf("Instruction breakpoint address: %x08\n", dataAddress);
} else {
log_print("Instruction breakpoint failed!\n");
}
}
setDataBreakpoint(0, false, false);
setInstructionBreakpoint(0);
rfi();
return 0;
}
#endif

38
src/system/threads.c Normal file
View File

@ -0,0 +1,38 @@
#include "threads.h"
#include "../utils/linked_list.h"
#include "../dynamic_libs/os_functions.h"
#include "../utils/logger.h"
#include "../main.h"
struct node *getAllThreads() {
log_init(COMPUTER_IP_ADDRESS);
struct node *threads = NULL;
int currentThreadAddress = OSGetCurrentThread();
log_printf("Thread address: %08x\n", currentThreadAddress);
int iterationThreadAddress = currentThreadAddress;
int temporaryThreadAddress;
// Follow "previous thread" pointers back to the beginning
while ((temporaryThreadAddress = *(int *) (iterationThreadAddress + PREVIOUS_THREAD)) != 0) {
log_printf("Temporary thread address going backwards: %08x\n", temporaryThreadAddress);
iterationThreadAddress = temporaryThreadAddress;
}
// Now iterate over all threads
while ((temporaryThreadAddress = *(int *) (iterationThreadAddress + NEXT_THREAD)) != 0) {
// Grab the thread's address
log_printf("Temporary thread address going forward: %08x\n", temporaryThreadAddress);
threads = insert(threads, (void *) iterationThreadAddress);
log_printf("Inserted: %08x\n", iterationThreadAddress);
iterationThreadAddress = temporaryThreadAddress;
}
// The previous while would skip the last thread so add it as well
threads = insert(threads, (void *) iterationThreadAddress);
log_printf("Inserted: %08x\n", iterationThreadAddress);
reverse(&threads);
return threads;
}

10
src/system/threads.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef TCPGECKO_THREADS_H
#define TCPGECKO_THREADS_H
#define THREAD_SIZE 0x6A0
#define PREVIOUS_THREAD 0x390
#define NEXT_THREAD 0x38C
struct node *getAllThreads();
#endif

View File

@ -17,7 +17,7 @@ void patchFunction(void *function, char *patchBytes, unsigned int patchBytesSize
log_print("Patching function...\n"); log_print("Patching function...\n");
void *patchAddress = function + functionOffset; void *patchAddress = function + functionOffset;
log_printf("Patch address: %p\n", patchAddress); log_printf("Patch address: %p\n", patchAddress);
kernelCopy((unsigned char *) patchAddress, (unsigned char *) patchBytes, patchBytesSize); kernelCopyInt((unsigned char *) patchAddress, (unsigned char *) patchBytes, patchBytesSize);
log_print("Successfully patched!\n"); log_print("Successfully patched!\n");
} }

View File

@ -1,3 +1,4 @@
#include "tcp_gecko.h"
#include <iosuhax.h> #include <iosuhax.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
@ -10,7 +11,6 @@
#include "main.h" #include "main.h"
#include "dynamic_libs/socket_functions.h" #include "dynamic_libs/socket_functions.h"
#include "dynamic_libs/gx2_functions.h" #include "dynamic_libs/gx2_functions.h"
#include "kernel/syscalls.h"
#include "dynamic_libs/fs_functions.h" #include "dynamic_libs/fs_functions.h"
#include "utils/logger.h" #include "utils/logger.h"
#include "system/memory.h" #include "system/memory.h"
@ -18,6 +18,7 @@
#include "utils/linked_list.h" #include "utils/linked_list.h"
#include "address.h" #include "address.h"
#include "system/stack.h" #include "system/stack.h"
#include "pause.h"
void *client; void *client;
void *commandBlock; void *commandBlock;
@ -68,6 +69,7 @@ struct pygecko_bss_t {
#define COMMAND_REMOVE_ALL_BREAKPOINTS 0xA6 #define COMMAND_REMOVE_ALL_BREAKPOINTS 0xA6
#define COMMAND_POKE_REGISTERS 0xA7 #define COMMAND_POKE_REGISTERS 0xA7
#define COMMAND_GET_STACK_TRACE 0xA8 #define COMMAND_GET_STACK_TRACE 0xA8
#define COMMAND_GET_ENTRY_POINT_ADDRESS 0xB1
#define COMMAND_RUN_KERNEL_COPY_SERVICE 0xCD #define COMMAND_RUN_KERNEL_COPY_SERVICE 0xCD
#define COMMAND_IOSU_HAX_READ_FILE 0xD0 #define COMMAND_IOSU_HAX_READ_FILE 0xD0
#define COMMAND_GET_VERSION_HASH 0xE0 #define COMMAND_GET_VERSION_HASH 0xE0
@ -76,13 +78,12 @@ struct pygecko_bss_t {
#define errno (*__gh_errno_ptr()) #define errno (*__gh_errno_ptr())
#define MSG_DONT_WAIT 32 #define MSG_DONT_WAIT 32
#define EWOULDBLOCK 6 #define EWOULDBLOCK 6
#define DATA_BUFFER_SIZE 0x5000
// #define WRITE_SCREEN_MESSAGE_BUFFER_SIZE 100 // #define WRITE_SCREEN_MESSAGE_BUFFER_SIZE 100
#define SERVER_VERSION "06/02/2017" #define SERVER_VERSION "06/03/2017"
#define ONLY_ZEROS_READ 0xB0 #define ONLY_ZEROS_READ 0xB0
#define NON_ZEROS_READ 0xBD #define NON_ZEROS_READ 0xBD
#define VERSION_HASH 0x39C9444B #define VERSION_HASH 0x3AC9444B
ZEXTERN int ZEXPORT ZEXTERN int ZEXPORT
deflateEnd OF((z_streamp deflateEnd OF((z_streamp
@ -100,61 +101,11 @@ int flush
// ########## Being kernel_copy.h ############ // ########## Being kernel_copy.h ############
// TODO Variable size, not hard-coded
unsigned char *memcpy_buffer[DATA_BUFFER_SIZE];
void pygecko_memcpy(unsigned char *destinationBuffer, unsigned char *sourceBuffer, unsigned int length) {
memcpy(memcpy_buffer, sourceBuffer, length);
SC0x25_KernelCopyData((unsigned int) OSEffectiveToPhysical(destinationBuffer), (unsigned int) &memcpy_buffer,
length);
DCFlushRange(destinationBuffer, (u32) length);
}
// ########## End kernel_copy.h ############ // ########## End kernel_copy.h ############
// ########## Being pause.h ############ // ########## Begin pause.h ############
int (*AVMGetDRCScanMode)(int);
unsigned long getConsoleStatePatchAddress() {
if (AVMGetDRCScanMode) {
log_print("Already acquired!\n");
} else {
// Acquire the RPL and function
log_print("Acquiring...\n");
unsigned int avm_handle;
OSDynLoad_Acquire("avm.rpl", (u32 *) &avm_handle);
ASSERT_ALLOCATED(avm_handle, "avm.rpl")
OSDynLoad_FindExport((u32) avm_handle, 0, "AVMGetDRCScanMode", &AVMGetDRCScanMode);
ASSERT_ALLOCATED(AVMGetDRCScanMode, "AVMGetDRCScanMode")
log_print("Acquired!\n");
}
return (unsigned long) (AVMGetDRCScanMode + 0x44);
}
typedef enum {
PAUSED = 0x38000001, RUNNING = 0x38000000
} ConsoleState;
void writeConsoleState(ConsoleState state) {
// Get the value to write
int patchValue = state;
log_printf("Patch value: %x\n", patchValue);
// Write the value
unsigned int patchAddress = getConsoleStatePatchAddress();
log_printf("Patch address: %x\n", patchAddress);
pygecko_memcpy((unsigned char *) patchAddress, (unsigned char *) &patchValue, 4);
}
bool isConsolePaused() {
unsigned int patchAddress = getConsoleStatePatchAddress();
log_printf("Patch address: %x\n", patchAddress);
int value = *(unsigned int *) patchAddress;
return value == PAUSED;
}
// ########## End pause.h ############ // ########## End pause.h ############
@ -327,7 +278,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
destinationAddress = ((int *) buffer)[0]; destinationAddress = ((int *) buffer)[0];
value = ((int *) buffer)[1]; value = ((int *) buffer)[1];
pygecko_memcpy((unsigned char *) destinationAddress, (unsigned char *) &value, 4); kernelCopyData((unsigned char *) destinationAddress, (unsigned char *) &value, 4);
break; break;
} }
case COMMAND_READ_MEMORY: { case COMMAND_READ_MEMORY: {
@ -374,15 +325,18 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
startingAddress += length; startingAddress += length;
} }
break; break;
} }
case COMMAND_READ_MEMORY_KERNEL: { case COMMAND_READ_MEMORY_KERNEL: {
const unsigned char *startingAddress, *endingAddress, *useKernRead; const unsigned char *startingAddress, *endingAddress, *useKernRead;
ret = recvwait(bss, clientfd, buffer, 3 * sizeof(int)); ret = recvwait(bss, clientfd, buffer, 3 * sizeof(int));
CHECK_ERROR(ret < 0) ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (receiving data)")
startingAddress = ((const unsigned char **) buffer)[0];
endingAddress = ((const unsigned char **) buffer)[1]; int bufferIndex = 0;
useKernRead = ((const unsigned char **) buffer)[2]; startingAddress = ((const unsigned char **) buffer)[bufferIndex++];
endingAddress = ((const unsigned char **) buffer)[bufferIndex++];
useKernRead = ((const unsigned char **) buffer)[bufferIndex];
while (startingAddress != endingAddress) { while (startingAddress != endingAddress) {
int length = (int) (endingAddress - startingAddress); int length = (int) (endingAddress - startingAddress);
@ -407,12 +361,11 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
ret = sendByte(bss, clientfd, ONLY_ZEROS_READ); ret = sendByte(bss, clientfd, ONLY_ZEROS_READ);
CHECK_ERROR(ret < 0) CHECK_ERROR(ret < 0)
} else { } else {
// Send the real bytes now
buffer[0] = NON_ZEROS_READ; buffer[0] = NON_ZEROS_READ;
if (useKernRead) { if (useKernRead) {
for (int offset = 0; offset < length; offset += sizeof(int)) { for (int offset = 0; offset < length; offset += 4) {
*((int *) (buffer + 1) + offset / sizeof(int)) = readKernelMemory(startingAddress + offset); *((int *) (buffer + 1) + offset / 4) = readKernelMemory(startingAddress + offset);
} }
} else { } else {
memcpy(buffer + 1, startingAddress, length); memcpy(buffer + 1, startingAddress, length);
@ -430,6 +383,77 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
startingAddress += length; startingAddress += length;
} }
break; break;
/* const unsigned char *startingAddress, *endingAddress, *useKernRead;
ret = recvwait(bss, clientfd, buffer, 3 * sizeof(int));
ASSERT_FUNCTION_SUCCEEDED(ret, "recvwait (receiving data)")
int bufferIndex = 0;
startingAddress = ((const unsigned char **) buffer)[bufferIndex++];
endingAddress = ((const unsigned char **) buffer)[bufferIndex++];
useKernRead = ((const unsigned char **) buffer)[bufferIndex];
while (startingAddress != endingAddress) {
log_printf("Reading memory from %08x to %08x with kernel %i\n", startingAddress, endingAddress,
useKernRead);
unsigned int length = (unsigned int) (endingAddress - startingAddress);
// Do not smash the buffer
if (length > DATA_BUFFER_SIZE) {
length = DATA_BUFFER_SIZE;
}
// Figure out if all bytes are zero to possibly avoid sending them
log_print("Checking for all zero bytes...\n");
unsigned int rangeIterationIndex = 0;
for (; rangeIterationIndex < length; rangeIterationIndex++) {
int character = useKernRead ? readKernelMemory(startingAddress + rangeIterationIndex)
: startingAddress[rangeIterationIndex];
if (character != 0) {
break;
}
}
log_print("Preparing to send...\n");
if (rangeIterationIndex == length) {
// No need to send all zero bytes for performance
log_print("All zero...\n");
ret = sendByte(bss, clientfd, ONLY_ZEROS_READ);
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (only zero bytes read byte)")
log_print("Sent!\n");
} else {
// Send the real bytes now
log_print("Real bytes...\n");
buffer[0] = NON_ZEROS_READ;
if (useKernRead) {
// kernelCopy(buffer + 1, (unsigned char *) startingAddress, length);
for (unsigned int offset = 0; offset < length; offset += sizeof(int)) {
*((int *) (buffer + 1) + offset / sizeof(int)) = readKernelMemory(
startingAddress + offset);
log_printf("Offset: %x\n", offset);
}
log_print("Done kernel reading!\n");
} else {
log_print("Memory copying...\n");
memcpy(buffer + 1, startingAddress, length);
log_print("Done copying!\n");
}
log_print("Sending everything...\n");
ret = sendwait(bss, clientfd, buffer, length + 1);
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (read bytes buffer)")
log_print("Sent!\n");
}
startingAddress += length;
}
log_print("Done reading...\n");
break;*/
} }
case COMMAND_VALIDATE_ADDRESS_RANGE: { case COMMAND_VALIDATE_ADDRESS_RANGE: {
ret = recvwait(bss, clientfd, buffer, 8); ret = recvwait(bss, clientfd, buffer, 8);
@ -671,7 +695,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
ret = recvwait(bss, clientfd, buffer, length); ret = recvwait(bss, clientfd, buffer, length);
CHECK_ERROR(ret < 0) CHECK_ERROR(ret < 0)
pygecko_memcpy(current_address, buffer, (unsigned int) length); kernelCopyData(current_address, buffer, (unsigned int) length);
current_address += length; current_address += length;
} }
@ -1209,7 +1233,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
// Write the assembly to an executable code region // Write the assembly to an executable code region
int destinationAddress = 0x10000000 - DATA_BUFFER_SIZE; int destinationAddress = 0x10000000 - DATA_BUFFER_SIZE;
pygecko_memcpy((unsigned char *) destinationAddress, buffer, DATA_BUFFER_SIZE); kernelCopyData((unsigned char *) destinationAddress, buffer, DATA_BUFFER_SIZE);
// Execute the assembly from there // Execute the assembly from there
void (*function)() = (void (*)()) destinationAddress; void (*function)() = (void (*)()) destinationAddress;
@ -1217,7 +1241,7 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
// Clear the memory contents again // Clear the memory contents again
memset((void *) buffer, 0, DATA_BUFFER_SIZE); memset((void *) buffer, 0, DATA_BUFFER_SIZE);
pygecko_memcpy((unsigned char *) destinationAddress, buffer, DATA_BUFFER_SIZE); kernelCopyData((unsigned char *) destinationAddress, buffer, DATA_BUFFER_SIZE);
break; break;
} }
@ -1336,7 +1360,23 @@ static int processCommands(struct pygecko_bss_t *bss, int clientfd) {
break; break;
} }
case COMMAND_POKE_REGISTERS: { case COMMAND_POKE_REGISTERS: {
log_print("Receiving poke registers data...\n");
int gprSize = 4 * 32;
int fprSize = 8 * 32;
ret = recvwait(bss, clientfd, buffer, gprSize + fprSize);
log_print("Poking registers...\n");
memcpy((void *) crashContext.gpr, (const void *) buffer, gprSize);
memcpy((void *) crashContext.fpr, (const void *) buffer, fprSize);
break;
}
case COMMAND_GET_ENTRY_POINT_ADDRESS: {
u32 *entryPointAddress = (u32 *) *((u32 *) OS_SPECIFICS->addr_OSTitle_main_entry);
((u32 *) buffer)[0] = (u32) entryPointAddress;
ret = sendwait(bss, clientfd, buffer, sizeof(int));
ASSERT_FUNCTION_SUCCEEDED(ret, "sendwait (Entry point address)");
break;
} }
case COMMAND_RUN_KERNEL_COPY_SERVICE: { case COMMAND_RUN_KERNEL_COPY_SERVICE: {
if (!kernelCopyServiceStarted) { if (!kernelCopyServiceStarted) {

View File

@ -1,15 +1,13 @@
#ifndef _PYGECKO_H_ #pragma once
#define _PYGECKO_H_
/* Main */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#define DATA_BUFFER_SIZE 0x5000
void startTCPGecko(void); void startTCPGecko(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif

17
src/title.c Normal file
View File

@ -0,0 +1,17 @@
#include "dynamic_libs/os_functions.h"
#include "title.h"
bool isRunningTitleID(unsigned long long int japaneseTitleID) {
unsigned long long int currentTitleID = (unsigned long long int) OSGetTitleID();
return currentTitleID == japaneseTitleID // JAP
|| currentTitleID == japaneseTitleID + 0x100 // USA
|| currentTitleID == japaneseTitleID + 0x200; // EUR
}
bool isRunningAllowedTitleID() {
return OSGetTitleID != 0
&& !isRunningTitleID(TITLE_ID_MII_VERSE)
&& !isRunningTitleID(TITLE_ID_MII_MAKER)
&& !isRunningTitleID(TITLE_ID_BAYONETTA_2)
&& !isRunningTitleID(TITLE_ID_INTERNET_BROWSER);
}

11
src/title.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef TCPGECKO_TITLE_H
#define TCPGECKO_TITLE_H
#define TITLE_ID_MII_VERSE 0x000500301001600A
#define TITLE_ID_MII_MAKER 0x000500101004A000
#define TITLE_ID_BAYONETTA_2 0x0005000010172500
#define TITLE_ID_INTERNET_BROWSER 0x000500301001200A
bool isRunningAllowedTitleID();
#endif

51
src/utils/linked_list.c Normal file
View File

@ -0,0 +1,51 @@
#include "linked_list.h"
#include <stdio.h>
#include <stdlib.h>
void destroy(struct node *list) {
struct node *currentNode = list;
while (currentNode != NULL) {
struct node *previousNode = currentNode;
currentNode = currentNode->next;
free(previousNode);
}
}
struct node *insert(struct node *list, void *data) {
size_t structureSize = sizeof(struct node);
struct node *addedNode = (struct node *) malloc(structureSize);
addedNode->data = data;
addedNode->next = list;
list = addedNode;
return list;
}
int length(struct node *list) {
int length = 0;
struct node *current;
for (current = list; current != NULL; current = current->next) {
length++;
}
return length;
}
void reverse(struct node **list) {
struct node *previous = NULL;
struct node *current = *list;
struct node *next;
while (current != NULL) {
next = current->next;
current->next = previous;
previous = current;
current = next;
}
*list = previous;
}

17
src/utils/linked_list.h Normal file
View File

@ -0,0 +1,17 @@
#ifndef LINKED_LIST_LINKED_DATA_LIST_H
#define LINKED_LIST_LINKED_DATA_LIST_H
struct node {
void *data;
struct node *next;
};
void destroy(struct node *list);
struct node *insert(struct node *list, void *data);
int length(struct node *list);
void reverse(struct node **list);
#endif

8
src/utils/stringify.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef TCPGECKO_STRINGIFY_H
#define TCPGECKO_STRINGIFY_H
// http://elixir.free-electrons.com/linux/v2.6.24/source/include/linux/stringify.h#L9
#define __stringify_1(x) #x
#define __stringify(x) __stringify_1(x)
#endif

Binary file not shown.