diff --git a/CMakeLists.txt b/CMakeLists.txt index 038fee9..8f94d0a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -28,6 +28,8 @@ set(PROJECT_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}) include_directories( ${PROJECT_ROOT_DIR}/src/core ${PROJECT_ROOT_DIR}/src/utils + ${PROJECT_ROOT_DIR}/src/reMarkable + ${PROJECT_ROOT_DIR}/libs/include ) # Find required libraries @@ -79,6 +81,7 @@ set(COMMON_SOURCES # reMarkable dylib set(REMARKABLE_SOURCES ${PROJECT_ROOT_DIR}/src/reMarkable/reMarkable.m + ${PROJECT_ROOT_DIR}/src/reMarkable/DevHooks.m ) add_library(reMarkable SHARED diff --git a/src/reMarkable/DevHooks.h b/src/reMarkable/DevHooks.h new file mode 100644 index 0000000..2e9c228 --- /dev/null +++ b/src/reMarkable/DevHooks.h @@ -0,0 +1,47 @@ +#ifndef DEV_HOOKS_H +#define DEV_HOOKS_H + +#ifdef BUILD_MODE_DEV + +#import +#include + +// Forward declarations for Qt types +class QIODevice; +class QObject; +namespace QtSharedPointer { + struct ExternalRefCountData; +} + +extern ssize_t (*original_qIODevice_write)(QIODevice *self, const char *data, int64_t maxSize); +extern int64_t (*original_qmlregister)(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int, int64_t, int, int64_t); +extern int64_t (*original_function_at_0x100011790)(uint64_t *a1); +extern int64_t (*original_function_at_0x100011CE0)(int64_t, const QObject *, unsigned char, int64_t, QtSharedPointer::ExternalRefCountData *); +extern int64_t (*original_function_at_0x10015A130)(int64_t, int64_t); +extern void (*original_function_at_0x10015BC90)(int64_t, int64_t); +extern int64_t (*original_function_at_0x10016D520)(int64_t, int64_t *, unsigned int, int64_t); +extern void (*original_function_at_0x1001B6EE0)(int64_t, int64_t *, unsigned int); + +#ifdef __cplusplus +extern "C" { +#endif + +ssize_t hooked_qIODevice_write(QIODevice *self, const char *data, int64_t maxSize); +int64_t hooked_qmlregister(int64_t, int64_t, int64_t, int64_t, int64_t, int64_t, int, int64_t, int, int64_t); +int64_t hooked_function_at_0x100011790(uint64_t *a1); +int64_t hooked_function_at_0x100011CE0(int64_t, const QObject *, unsigned char, int64_t, QtSharedPointer::ExternalRefCountData *); +int64_t hooked_function_at_0x10015A130(int64_t, int64_t); +void hooked_function_at_0x10015BC90(int64_t, int64_t); +int64_t hooked_function_at_0x10016D520(int64_t, int64_t *, unsigned int, int64_t); +void hooked_function_at_0x1001B6EE0(int64_t, int64_t *, unsigned int); + +#ifdef __cplusplus +} +#endif + +void logMemory(const char *label, void *address, size_t length); +void logStackTrace(const char *label); + +#endif // BUILD_MODE_DEV + +#endif // DEV_HOOKS_H \ No newline at end of file diff --git a/src/reMarkable/DevHooks.m b/src/reMarkable/DevHooks.m new file mode 100644 index 0000000..591d126 --- /dev/null +++ b/src/reMarkable/DevHooks.m @@ -0,0 +1,389 @@ +#ifdef BUILD_MODE_DEV + +#import "DevHooks.h" +#import "Logger.h" +#import +#include +#include + +#include +#include + +// Original function pointers +ssize_t (*original_qIODevice_write)(QIODevice *self, const char *data, int64_t maxSize) = NULL; + +int64_t (*original_qmlregister)( + int64_t a1, + int64_t a2, + int64_t a3, + int64_t a4, + int64_t a5, + int64_t a6, + int a7, + int64_t a8, + int a9, + int64_t a10) = NULL; + +int64_t (*original_function_at_0x100011790)(uint64_t *a1) = NULL; +int64_t (*original_function_at_0x100011CE0)(int64_t a1, const QObject *a2, unsigned char a3, int64_t a4, QtSharedPointer::ExternalRefCountData *a5) = NULL; +int64_t (*original_function_at_0x10015A130)(int64_t a1, int64_t a2) = NULL; +void (*original_function_at_0x10015BC90)(int64_t a1, int64_t a2) = NULL; +int64_t (*original_function_at_0x10016D520)(int64_t a1, int64_t *a2, unsigned int a3, int64_t a4) = NULL; +void (*original_function_at_0x1001B6EE0)(int64_t a1, int64_t *a2, unsigned int a3) = NULL; + +#pragma mark - Helper Functions + +void logMemory(const char *label, void *address, size_t length) { + if (!address) { + NSLogger(@"[reMarkable] %s: (null)", label); + return; + } + + unsigned char *ptr = (unsigned char *)address; + NSMutableString *hexLine = [NSMutableString stringWithFormat:@"[reMarkable] %s: ", label]; + + for (size_t i = 0; i < length; i++) { + [hexLine appendFormat:@"%02x ", ptr[i]]; + if ((i + 1) % 16 == 0 && i < length - 1) { + NSLogger(@"%@", hexLine); + hexLine = [NSMutableString stringWithString:@"[reMarkable] "]; + } + } + + // Log remaining bytes if any + if ([hexLine length] > 28) { // More than just the prefix + NSLogger(@"%@", hexLine); + } +} + +void logStackTrace(const char *label) { + NSLogger(@"[reMarkable] %s - Stack trace:", label); + NSArray *callStack = [NSThread callStackSymbols]; + NSUInteger count = [callStack count]; + + for (NSUInteger i = 0; i < count; i++) { + NSString *frame = callStack[i]; + NSLogger(@"[reMarkable] #%lu: %@", (unsigned long)i, frame); + } +} + +#pragma mark - Hook Implementations + +extern "C" ssize_t hooked_qIODevice_write( + QIODevice *self, + const char *data, + int64_t maxSize) { + NSLogger(@"[reMarkable] QIODevice::write called with maxSize: %lld", (long long)maxSize); + + logStackTrace("QIODevice::write call stack"); + logMemory("Data to write", (void *)data, (size_t)(maxSize < 64 ? maxSize : 64)); + + if (original_qIODevice_write) { + ssize_t result = original_qIODevice_write(self, data, maxSize); + NSLogger(@"[reMarkable] QIODevice::write result: %zd", result); + return result; + } + NSLogger(@"[reMarkable] WARNING: Original QIODevice::write not available, returning 0"); + return 0; +} + +extern "C" int64_t hooked_function_at_0x100011790(uint64_t *a1) { + NSLogger(@"[reMarkable] Hook at 0x100011790 called!"); + NSLogger(@"[reMarkable] a1 = %p", a1); + + if (a1) { + NSLogger(@"[reMarkable] *a1 = 0x%llx", (unsigned long long)*a1); + logMemory("Memory at a1", (void *)a1, 64); + logMemory("Memory at *a1", (void *)(*a1), 64); + } else { + NSLogger(@"[reMarkable] a1 is NULL"); + } + + if (original_function_at_0x100011790) { + int64_t result = original_function_at_0x100011790(a1); + NSLogger(@"[reMarkable] result = 0x%llx", (unsigned long long)result); + return result; + } + + NSLogger(@"[reMarkable] WARNING: Original function at 0x100011790 not available, returning 0"); + return 0; +} + +extern "C" int64_t hooked_function_at_0x100011CE0( + int64_t a1, + const QObject *a2, + unsigned char a3, + int64_t a4, + QtSharedPointer::ExternalRefCountData *a5) { + // This function appears to be a QML type registration wrapper + // It calls QQmlPrivate::qmlregister(3, ®istrationData) + // + // Based on IDA analysis: + // - a1: stored at offset +0x8 in registration struct (likely type metadata ptr) + // - a2: NOT actually a QObject* - low bits used as: ((_WORD)a2 << 8) | a3 + // This suggests a2's low 16 bits are a version/revision number + // - a3: combined with a2 to form v17 (flags/version field) + // - a4: stored at offset +0x18 (likely URI or type info pointer) + // - a5: ExternalRefCountData* for shared pointer ref counting + + NSLogger(@"[reMarkable] ========================================"); + NSLogger(@"[reMarkable] Hook at 0x100011CE0 (QML Type Registration)"); + NSLogger(@"[reMarkable] ========================================"); + + NSLogger(@"[reMarkable] a1 (typeMetadata?) = 0x%llx", (unsigned long long)a1); + + uint16_t a2_low = (uint16_t)(uintptr_t)a2; + uint16_t combined_v17 = (a2_low << 8) | a3; + NSLogger(@"[reMarkable] a2 (raw) = %p (0x%llx)", a2, (unsigned long long)(uintptr_t)a2); + NSLogger(@"[reMarkable] a2 low 16 bits = 0x%04x (%u)", a2_low, a2_low); + NSLogger(@"[reMarkable] a3 (flags/version) = 0x%02x (%u)", a3, a3); + NSLogger(@"[reMarkable] v17 = (a2<<8)|a3 = 0x%04x (%u)", combined_v17, combined_v17); + NSLogger(@"[reMarkable] a4 (typeInfo/URI?) = 0x%llx", (unsigned long long)a4); + NSLogger(@"[reMarkable] a5 (refCountData) = %p", a5); + + if (a1) { + logMemory("Memory at a1 (typeMetadata)", (void *)a1, 64); + void **vtable = (void **)a1; + NSLogger(@"[reMarkable] a1 vtable/first ptr = %p", *vtable); + } + + if (a4) { + logMemory("Memory at a4 (typeInfo)", (void *)a4, 64); + const char *maybeStr = (const char *)a4; + bool isPrintable = true; + int len = 0; + for (int i = 0; i < 64 && maybeStr[i]; i++) { + if (maybeStr[i] < 0x20 || maybeStr[i] > 0x7e) { + isPrintable = false; + break; + } + len++; + } + if (isPrintable && len > 0) { + NSLogger(@"[reMarkable] a4 as string: \"%.*s\"", len, maybeStr); + } + } + + if (a5) { + logMemory("Memory at a5 (refCountData)", (void *)a5, 32); + } + + logStackTrace("QML Registration context"); + + if (original_function_at_0x100011CE0) { + int64_t result = original_function_at_0x100011CE0(a1, a2, a3, a4, a5); + NSLogger(@"[reMarkable] result (qmlregister return) = %u (0x%x)", (unsigned int)result, (unsigned int)result); + NSLogger(@"[reMarkable] ========================================"); + return result; + } + + NSLogger(@"[reMarkable] WARNING: Original function at 0x100011CE0 not available, returning 0"); + return 0; +} + +extern "C" int64_t hooked_function_at_0x10015A130(int64_t a1, int64_t a2) { + NSLogger(@"[reMarkable] Hook at 0x10015A130 called!"); + NSLogger(@"[reMarkable] a1 = 0x%llx", (unsigned long long)a1); + NSLogger(@"[reMarkable] a2 = 0x%llx", (unsigned long long)a2); + + logMemory("Memory at a1", (void *)a1, 64); + logMemory("Memory at a2", (void *)a2, 64); + + if (original_function_at_0x10015A130) { + int64_t result = original_function_at_0x10015A130(a1, a2); + NSLogger(@"[reMarkable] result = 0x%llx", (unsigned long long)result); + return result; + } + + NSLogger(@"[reMarkable] WARNING: Original function at 0x10015A130 not available, returning 0"); + return 0; +} + +extern "C" void hooked_function_at_0x10015BC90(int64_t a1, int64_t a2) { + NSLogger(@"[reMarkable] Hook at 0x10015BC90 called!"); + NSLogger(@"[reMarkable] a1 = 0x%llx", (unsigned long long)a1); + NSLogger(@"[reMarkable] a2 = 0x%llx", (unsigned long long)a2); + + logMemory("Memory at a1", (void *)a1, 64); + logMemory("Memory at a2", (void *)a2, 64); + + if (original_function_at_0x10015BC90) { + original_function_at_0x10015BC90(a1, a2); + NSLogger(@"[reMarkable] original function returned (void)"); + return; + } + + NSLogger(@"[reMarkable] WARNING: Original function at 0x10015BC90 not available"); +} + +extern "C" int64_t hooked_function_at_0x10016D520(int64_t a1, int64_t *a2, unsigned int a3, int64_t a4) { + NSLogger(@"[reMarkable] Hook at 0x10016D520 called!"); + NSLogger(@"[reMarkable] a1 = 0x%llx", (unsigned long long)a1); + NSLogger(@"[reMarkable] a2 = %p", a2); + if (a2) { + NSLogger(@"[reMarkable] *a2 = 0x%llx", (unsigned long long)*a2); + } + NSLogger(@"[reMarkable] a3 = %u (0x%x)", a3, a3); + NSLogger(@"[reMarkable] a4 = 0x%llx", (unsigned long long)a4); + + logMemory("Memory at a1", (void *)a1, 64); + logMemory("Memory at a2", (void *)a2, 64); + + if (a2 && *a2 != 0) { + logMemory("Memory at *a2", (void *)*a2, 64); + } + + logMemory("Memory at a4", (void *)a4, 64); + + if (original_function_at_0x10016D520) { + int64_t result = original_function_at_0x10016D520(a1, a2, a3, a4); + NSLogger(@"[reMarkable] result = 0x%llx", (unsigned long long)result); + return result; + } + + NSLogger(@"[reMarkable] WARNING: Original function not available, returning 0"); + return 0; +} + +extern "C" void hooked_function_at_0x1001B6EE0(int64_t a1, int64_t *a2, unsigned int a3) { + NSLogger(@"[reMarkable] Hook at 0x1001B6EE0 called!"); + NSLogger(@"[reMarkable] a1 = 0x%llx", (unsigned long long)a1); + + // At a1 (PdfExporter object): + // +0x10 contains a QString (likely document name) + NSLogger(@"[reMarkable] Reading QString at a1+0x10:"); + logMemory("a1 + 0x10 (raw)", (void *)(a1 + 0x10), 64); + + void **qstrPtr = (void **)(a1 + 0x10); + void *dataPtr = *qstrPtr; + + if (!dataPtr) { + NSLogger(@"[reMarkable] QString has null data pointer"); + return; + } + + // Try reading potential size fields near dataPtr + int32_t size = 0; + for (int delta = 4; delta <= 32; delta += 4) { + int32_t candidate = *(int32_t *)((char *)dataPtr - delta); + if (candidate > 0 && candidate < 10000) { + size = candidate; + NSLogger(@"[reMarkable] QString plausible size=%d (found at -%d)", size, delta); + break; + } + } + + if (size > 0) { + NSString *qstringValue = [[NSString alloc] initWithCharacters:(unichar *)dataPtr length:size]; + NSLogger(@"[reMarkable] QString value: \"%@\"", qstringValue); + } else { + NSLogger(@"[reMarkable] QString: could not find valid size"); + } + + NSLogger(@"[reMarkable] a2 = %p", a2); + if (a2) { + NSLogger(@"[reMarkable] *a2 = 0x%llx", (unsigned long long)*a2); + } + NSLogger(@"[reMarkable] a3 = %u (0x%x)", a3, a3); + + if (original_function_at_0x1001B6EE0) { + original_function_at_0x1001B6EE0(a1, a2, a3); + NSLogger(@"[reMarkable] Original function at 0x1001B6EE0 executed"); + } else { + NSLogger(@"[reMarkable] WARNING: Original function not available"); + } +} + +extern "C" int64_t hooked_qmlregister( + int64_t a1, + int64_t a2, + int64_t a3, + int64_t a4, + int64_t a5, + int64_t a6, + int a7, + int64_t a8, + int a9, + int64_t a10) { + + NSLogger(@"[reMarkable] ========================================"); + NSLogger(@"[reMarkable] QQmlPrivate::qmlregister called!"); + NSLogger(@"[reMarkable] ========================================"); + NSLogger(@"[reMarkable] a1 (RegistrationType) = 0x%llx (%lld)", (unsigned long long)a1, (long long)a1); + NSLogger(@"[reMarkable] a2 = 0x%llx (%lld)", (unsigned long long)a2, (long long)a2); + NSLogger(@"[reMarkable] a3 = 0x%llx (%lld)", (unsigned long long)a3, (long long)a3); + NSLogger(@"[reMarkable] a4 = 0x%llx (%lld)", (unsigned long long)a4, (long long)a4); + NSLogger(@"[reMarkable] a5 = 0x%llx (%lld)", (unsigned long long)a5, (long long)a5); + NSLogger(@"[reMarkable] a6 = 0x%llx (%lld)", (unsigned long long)a6, (long long)a6); + NSLogger(@"[reMarkable] a7 = 0x%x (%d)", a7, a7); + NSLogger(@"[reMarkable] a8 = 0x%llx (%lld)", (unsigned long long)a8, (long long)a8); + NSLogger(@"[reMarkable] a9 = 0x%x (%d)", a9, a9); + NSLogger(@"[reMarkable] a10 = 0x%llx (%lld)", (unsigned long long)a10, (long long)a10); + + // Check for PlatformHelpers registration + // a1 == 0 means TypeRegistration (object registration) + // a4 must be a valid pointer (not a small integer like 0, 1, 2, etc.) + if (a1 == 0 && a4 > 0x10000) { + const char *typeName = (const char *)a4; + + int len = 0; + bool isValid = true; + for (int i = 0; i < 256; i++) { + char c = typeName[i]; + if (c == '\0') { + break; + } + if (c < 0x20 || c > 0x7e) { + isValid = false; + break; + } + len++; + } + + if (isValid && len > 0) { + NSLogger(@"[reMarkable] typeName (a4) = \"%.*s\"", len, typeName); + + if (len == 15 && strncmp(typeName, "PlatformHelpers", 15) == 0) { + NSLogger(@"[reMarkable] !!! FOUND PlatformHelpers type registration !!!"); + NSLogger(@"[reMarkable] factory ptr (a2) = %p", (void *)a2); + NSLogger(@"[reMarkable] a3 (metaObject?) = %p", (void *)a3); + NSLogger(@"[reMarkable] a5 = %p", (void *)a5); + NSLogger(@"[reMarkable] a6 = %p", (void *)a6); + logMemory("Factory ptr memory", (void *)a2, 64); + logMemory("a3 memory (metaObject?)", (void *)a3, 64); + logStackTrace("PlatformHelpers registration"); + } + } + } + + // Try to interpret a2 as memory region for other registration types + if (a2 > 0x10000 && a1 != 0) { + logMemory("Memory at a2", (void *)a2, 64); + const char *maybeStr = (const char *)a2; + bool isPrintable = true; + int len = 0; + for (int i = 0; i < 128 && maybeStr[i]; i++) { + if (maybeStr[i] < 0x20 || maybeStr[i] > 0x7e) { + isPrintable = false; + break; + } + len++; + } + if (isPrintable && len > 0) { + NSLogger(@"[reMarkable] a2 as string: \"%.*s\"", len, maybeStr); + } + } + + int64_t result = 0; + if (original_qmlregister) { + result = original_qmlregister(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10); + NSLogger(@"[reMarkable] result = 0x%llx (%lld)", (unsigned long long)result, (long long)result); + } else { + NSLogger(@"[reMarkable] WARNING: Original qmlregister not available!"); + } + + NSLogger(@"[reMarkable] ========================================"); + return result; +} + +#endif // BUILD_MODE_DEV diff --git a/src/reMarkable/reMarkable.m b/src/reMarkable/reMarkable.m index 6e617fb..7760156 100644 --- a/src/reMarkable/reMarkable.m +++ b/src/reMarkable/reMarkable.m @@ -4,6 +4,9 @@ #import "MemoryUtils.h" #import "Logger.h" #import "ResourceUtils.h" +#ifdef BUILD_MODE_DEV +#import "DevHooks.h" +#endif #import #import #include @@ -26,6 +29,7 @@ #include #include + static NSString *const kReMarkableConfigFileName = @"rmfakecloud.config"; static NSString *const kReMarkableConfigHostKey = @"host"; static NSString *const kReMarkableConfigPortKey = @"port"; @@ -248,63 +252,7 @@ static int (*original_qRegisterResourceData)( const unsigned char *) = NULL; #endif -#ifdef BUILD_MODE_DEV -static ssize_t (*original_qIODevice_write)( - QIODevice *self, - const char *data, - qint64 maxSize) = NULL; -// Hook for function at 0x10015A130 -static int64_t (*original_function_at_0x10015A130)(int64_t a1, int64_t a2) = NULL; - -// Hook for function at 0x10015BC90 -static void (*original_function_at_0x10015BC90)(int64_t a1, int64_t a2) = NULL; - -// Hook for function at 0x10016D520 -static int64_t (*original_function_at_0x10016D520)(int64_t a1, int64_t *a2, unsigned int a3, int64_t a4) = NULL; - -// Hook for function at 0x1001B6EE0 -static void (*original_function_at_0x1001B6EE0)(int64_t a1, int64_t *a2, unsigned int a3) = NULL; -#endif - -#if defined(BUILD_MODE_DEV) -// Memory logging helper function -static void logMemory(const char *label, void *address, size_t length) { - if (!address) { - NSLogger(@"[reMarkable] %s: (null)", label); - return; - } - - unsigned char *ptr = (unsigned char *)address; - NSMutableString *hexLine = [NSMutableString stringWithFormat:@"[reMarkable] %s: ", label]; - - for (size_t i = 0; i < length; i++) { - [hexLine appendFormat:@"%02x ", ptr[i]]; - if ((i + 1) % 16 == 0 && i < length - 1) { - NSLogger(@"%@", hexLine); - hexLine = [NSMutableString stringWithString:@"[reMarkable] "]; - } - } - - // Log remaining bytes if any - if ([hexLine length] > 28) { // More than just the prefix - NSLogger(@"%@", hexLine); - } -} - -// Stack trace logging helper function -static void logStackTrace(const char *label) { - NSLogger(@"[reMarkable] %s - Stack trace:", label); - NSArray *callStack = [NSThread callStackSymbols]; - NSUInteger count = [callStack count]; - - // Skip first 2 frames (this function and the immediate caller's logging statement) - for (NSUInteger i = 0; i < count; i++) { - NSString *frame = callStack[i]; - NSLogger(@"[reMarkable] #%lu: %@", (unsigned long)i, frame); - } -} -#endif #ifdef BUILD_MODE_RMFAKECLOUD static inline bool shouldPatchURL(const QString &host) { @@ -362,13 +310,6 @@ static inline bool shouldPatchURL(const QString &host) { #endif #ifdef BUILD_MODE_DEV - // // Hook function at address 0x1???? - // [MemoryUtils hookAddress:@"reMarkable" - // staticAddress:0x???? - // hookFunction:(void *)hooked_function_at_0x???? - // originalFunction:(void **)&original_function_at_0x???? - // logPrefix:@"[reMarkable]"]; - NSLogger(@"[reMarkable] Build mode: dev/reverse engineering"); // [MemoryUtils hookSymbol:@"QtCore" // symbolName:@"__ZN9QIODevice5writeEPKcx" @@ -403,6 +344,29 @@ static inline bool shouldPatchURL(const QString &host) { // hookFunction:(void *)hooked_function_at_0x1001B6EE0 // originalFunction:(void **)&original_function_at_0x1001B6EE0 // logPrefix:@"[reMarkable]"]; + + // PlatformHelpers.exportFile implementation WIP + + // // Hook function at address 0x100011790 + // [MemoryUtils hookAddress:@"reMarkable" + // staticAddress:0x100011790 + // hookFunction:(void *)hooked_function_at_0x100011790 + // originalFunction:(void **)&original_function_at_0x100011790 + // logPrefix:@"[reMarkable]"]; + + // // Hook function at address 0x100011CE0 + // [MemoryUtils hookAddress:@"reMarkable" + // staticAddress:0x100011CE0 + // hookFunction:(void *)hooked_function_at_0x100011CE0 + // originalFunction:(void **)&original_function_at_0x100011CE0 + // logPrefix:@"[reMarkable]"]; + + // [MemoryUtils hookSymbol:@"QtQml" + // symbolName:@"__ZN11QQmlPrivate11qmlregisterENS_16RegistrationTypeEPv" + // hookFunction:(void *)hooked_qmlregister + // originalFunction:(void **)&original_qmlregister + // logPrefix:@"[reMarkable]"]; + #endif return YES; @@ -509,141 +473,4 @@ extern "C" int hooked_qRegisterResourceData( } #endif // BUILD_MODE_QMLDIFF -#ifdef BUILD_MODE_DEV -extern "C" ssize_t hooked_qIODevice_write( - QIODevice *self, - const char *data, - qint64 maxSize) { - NSLogger(@"[reMarkable] QIODevice::write called with maxSize: %lld", (long long)maxSize); - - // Log the call stack - logStackTrace("QIODevice::write call stack"); - - // Log the data to write - logMemory("Data to write", (void *)data, (size_t)(maxSize < 64 ? maxSize : 64)); - - if (original_qIODevice_write) { - ssize_t result = original_qIODevice_write(self, data, maxSize); - NSLogger(@"[reMarkable] QIODevice::write result: %zd", result); - return result; - } - NSLogger(@"[reMarkable] WARNING: Original QIODevice::write not available, returning 0"); - return 0; -} - -extern "C" int64_t hooked_function_at_0x10015A130(int64_t a1, int64_t a2) { - NSLogger(@"[reMarkable] Hook at 0x10015A130 called!"); - NSLogger(@"[reMarkable] a1 = 0x%llx", (unsigned long long)a1); - NSLogger(@"[reMarkable] a2 = 0x%llx", (unsigned long long)a2); - - logMemory("Memory at a1", (void *)a1, 64); - logMemory("Memory at a2", (void *)a2, 64); - - if (original_function_at_0x10015A130) { - int64_t result = original_function_at_0x10015A130(a1, a2); - NSLogger(@"[reMarkable] result = 0x%llx", (unsigned long long)result); - return result; - } - - NSLogger(@"[reMarkable] WARNING: Original function at 0x10015A130 not available, returning 0"); - return 0; -} - -extern "C" void hooked_function_at_0x10015BC90(int64_t a1, int64_t a2) { - NSLogger(@"[reMarkable] Hook at 0x10015BC90 called!"); - NSLogger(@"[reMarkable] a1 = 0x%llx", (unsigned long long)a1); - NSLogger(@"[reMarkable] a2 = 0x%llx", (unsigned long long)a2); - - logMemory("Memory at a1", (void *)a1, 64); - logMemory("Memory at a2", (void *)a2, 64); - - if (original_function_at_0x10015BC90) { - original_function_at_0x10015BC90(a1, a2); - NSLogger(@"[reMarkable] original function returned (void)"); - return; - } - - NSLogger(@"[reMarkable] WARNING: Original function at 0x10015BC90 not available"); -} - -extern "C" int64_t hooked_function_at_0x10016D520(int64_t a1, int64_t *a2, unsigned int a3, int64_t a4) { - NSLogger(@"[reMarkable] Hook at 0x10016D520 called!"); - NSLogger(@"[reMarkable] a1 = 0x%llx", (unsigned long long)a1); - NSLogger(@"[reMarkable] a2 = %p", a2); - if (a2) { - NSLogger(@"[reMarkable] *a2 = 0x%llx", (unsigned long long)*a2); - } - NSLogger(@"[reMarkable] a3 = %u (0x%x)", a3, a3); - NSLogger(@"[reMarkable] a4 = 0x%llx", (unsigned long long)a4); - - // Log memory contents using helper function - logMemory("Memory at a1", (void *)a1, 64); - logMemory("Memory at a2", (void *)a2, 64); - - if (a2 && *a2 != 0) { - logMemory("Memory at *a2", (void *)*a2, 64); - } - - logMemory("Memory at a4", (void *)a4, 64); - - if (original_function_at_0x10016D520) { - int64_t result = original_function_at_0x10016D520(a1, a2, a3, a4); - NSLogger(@"[reMarkable] result = 0x%llx", (unsigned long long)result); - return result; - } - - NSLogger(@"[reMarkable] WARNING: Original function not available, returning 0"); - return 0; -} - -extern "C" void hooked_function_at_0x1001B6EE0(int64_t a1, int64_t *a2, unsigned int a3) { - NSLogger(@"[reMarkable] Hook at 0x1001B6EE0 called!"); - NSLogger(@"[reMarkable] a1 = 0x%llx", (unsigned long long)a1); - - // At a1 (PdfExporter object at 0x7ff4c17391e0): - // +0x10 0x000600043EC10 QString (likely document name) - NSLogger(@"[reMarkable] Reading QString at a1+0x10:"); - logMemory("a1 + 0x10 (raw)", (void *)(a1 + 0x10), 64); - - void **qstrPtr = (void **)(a1 + 0x10); - void *dataPtr = *qstrPtr; - - if (!dataPtr) { - NSLogger(@"[reMarkable] QString has null data pointer"); - return; - } - - // try reading potential size fields near dataPtr - int32_t size = 0; - for (int delta = 4; delta <= 32; delta += 4) { - int32_t candidate = *(int32_t *)((char *)dataPtr - delta); - if (candidate > 0 && candidate < 10000) { - size = candidate; - NSLogger(@"[reMarkable] QString plausible size=%d (found at -%d)", size, delta); - break; - } - } - - if (size > 0) { - NSString *qstringValue = [[NSString alloc] initWithCharacters:(unichar *)dataPtr length:size]; - NSLogger(@"[reMarkable] QString value: \"%@\"", qstringValue); - } else { - NSLogger(@"[reMarkable] QString: could not find valid size"); - } - - NSLogger(@"[reMarkable] a2 = %p", a2); - if (a2) { - NSLogger(@"[reMarkable] *a2 = 0x%llx", (unsigned long long)*a2); - } - NSLogger(@"[reMarkable] a3 = %u (0x%x)", a3, a3); - - if (original_function_at_0x1001B6EE0) { - original_function_at_0x1001B6EE0(a1, a2, a3); - NSLogger(@"[reMarkable] Original function at 0x1001B6EE0 executed"); - } else { - NSLogger(@"[reMarkable] WARNING: Original function not available"); - } -} -#endif // BUILD_MODE_DEV - @end \ No newline at end of file