mirror of
https://github.com/NohamR/RMHook.git
synced 2026-01-09 05:58:12 +00:00
Compare commits
2 Commits
18abae42b7
...
15e5dabc37
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15e5dabc37 | ||
|
|
1619fda631 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
build/
|
||||
.DS_Store
|
||||
/.vscode
|
||||
/research
|
||||
|
||||
@@ -6,6 +6,14 @@ enable_language(OBJC OBJCXX)
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
# Build mode options
|
||||
# - rmfakecloud: Redirect reMarkable cloud to rmfakecloud server (default)
|
||||
# - qmldiff: Qt resource data registration hooking (WIP)
|
||||
# - dev: Development/reverse engineering mode with all hooks
|
||||
option(BUILD_MODE_RMFAKECLOUD "Build with rmfakecloud support" ON)
|
||||
option(BUILD_MODE_QMLDIFF "Build with QML diff/resource hooking" OFF)
|
||||
option(BUILD_MODE_DEV "Build with dev/reverse engineering hooks" OFF)
|
||||
|
||||
# Compiler settings for macOS
|
||||
set(CMAKE_MACOSX_RPATH 1)
|
||||
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "Minimum OS X deployment version")
|
||||
@@ -93,8 +101,24 @@ set_target_properties(reMarkable PROPERTIES
|
||||
|
||||
add_definitions(-DQT_NO_VERSION_TAGGING)
|
||||
|
||||
# Add build mode compile definitions
|
||||
if(BUILD_MODE_RMFAKECLOUD)
|
||||
target_compile_definitions(reMarkable PRIVATE BUILD_MODE_RMFAKECLOUD=1)
|
||||
message(STATUS "Build mode: rmfakecloud (cloud redirection)")
|
||||
endif()
|
||||
|
||||
if(BUILD_MODE_QMLDIFF)
|
||||
target_compile_definitions(reMarkable PRIVATE BUILD_MODE_QMLDIFF=1)
|
||||
message(STATUS "Build mode: qmldiff (resource hooking)")
|
||||
endif()
|
||||
|
||||
if(BUILD_MODE_DEV)
|
||||
target_compile_definitions(reMarkable PRIVATE BUILD_MODE_DEV=1)
|
||||
message(STATUS "Build mode: dev (reverse engineering)")
|
||||
endif()
|
||||
|
||||
target_link_libraries(reMarkable PRIVATE
|
||||
${LIBS}
|
||||
${QT_LIB_TARGETS}
|
||||
/opt/homebrew/Cellar/libzip/1.11.4/lib/intel/libzstd.1.5.7.dylib
|
||||
${PROJECT_ROOT_DIR}/libs/libzstd.1.dylib
|
||||
)
|
||||
22
README.md
22
README.md
@@ -37,6 +37,7 @@ Use the provided injection script:
|
||||
|
||||
This script will:
|
||||
- Copy the dylib to the app bundle's Resources folder
|
||||
- Copy the `libzstd.1.dylib` dependency and fix library references
|
||||
- Inject the load command into the executable using `optool`
|
||||
- Remove the code signature and resign with ad-hoc signature
|
||||
- Remove the `_MASReceipt` folder
|
||||
@@ -145,5 +146,24 @@ cd RMHook
|
||||
|
||||
2. **Compile the dylib:**
|
||||
```bash
|
||||
./scripts/build.sh
|
||||
./scripts/build.sh [mode]
|
||||
```
|
||||
|
||||
### Build modes
|
||||
|
||||
The build script supports different modes for various use cases:
|
||||
|
||||
| Mode | Description |
|
||||
|------|-------------|
|
||||
| `rmfakecloud` | Redirect reMarkable cloud to rmfakecloud server (default) |
|
||||
| `qmldiff` | Qt resource data registration hooking (WIP) |
|
||||
| `dev` | Development/reverse engineering mode with all hooks |
|
||||
| `all` | Enable all modes |
|
||||
|
||||
Examples:
|
||||
```bash
|
||||
./scripts/build.sh # Build with rmfakecloud mode (default)
|
||||
./scripts/build.sh rmfakecloud # Explicitly build rmfakecloud mode
|
||||
./scripts/build.sh dev # Build with dev/reverse engineering hooks
|
||||
./scripts/build.sh all # Build with all modes enabled
|
||||
```
|
||||
BIN
libs/libzstd.1.dylib
Normal file
BIN
libs/libzstd.1.dylib
Normal file
Binary file not shown.
@@ -1,14 +1,42 @@
|
||||
#!/bin/bash
|
||||
# Script to compile the reMarkable dylib
|
||||
# Script to compile the reMarkable dylib with different build modes
|
||||
|
||||
# Build modes:
|
||||
# rmfakecloud - Redirect reMarkable cloud to rmfakecloud server (default)
|
||||
# qmldiff - Qt resource data registration hooking (WIP)
|
||||
# dev - Development/reverse engineering mode with all hooks
|
||||
|
||||
# By default, compile reMarkable
|
||||
APP_NAME=${1:-reMarkable}
|
||||
PROJECT_DIR=$(cd "$(dirname "$0")/.." && pwd)
|
||||
|
||||
# Qt path detection (adjust according to your installation)
|
||||
QT_PATH=${QT_PATH:-"$HOME/Qt/6.10.0"}
|
||||
# Qt path detection
|
||||
QT_PATH=${QT_PATH:-$(ls -d "$HOME/Qt/6."* 2>/dev/null | sort -V | tail -n1)}
|
||||
|
||||
echo "🔨 Compiling $APP_NAME.dylib..."
|
||||
# Parse build mode argument
|
||||
BUILD_MODE=${1:-rmfakecloud}
|
||||
|
||||
# Set CMake options based on build mode
|
||||
CMAKE_OPTIONS=""
|
||||
case "$BUILD_MODE" in
|
||||
rmfakecloud)
|
||||
CMAKE_OPTIONS="-DBUILD_MODE_RMFAKECLOUD=ON -DBUILD_MODE_QMLDIFF=OFF -DBUILD_MODE_DEV=OFF"
|
||||
;;
|
||||
qmldiff)
|
||||
CMAKE_OPTIONS="-DBUILD_MODE_RMFAKECLOUD=OFF -DBUILD_MODE_QMLDIFF=ON -DBUILD_MODE_DEV=OFF"
|
||||
;;
|
||||
dev)
|
||||
CMAKE_OPTIONS="-DBUILD_MODE_RMFAKECLOUD=OFF -DBUILD_MODE_QMLDIFF=OFF -DBUILD_MODE_DEV=ON"
|
||||
;;
|
||||
all)
|
||||
CMAKE_OPTIONS="-DBUILD_MODE_RMFAKECLOUD=ON -DBUILD_MODE_QMLDIFF=ON -DBUILD_MODE_DEV=ON"
|
||||
;;
|
||||
*)
|
||||
echo "❌ Unknown build mode: $BUILD_MODE"
|
||||
echo "Available modes: rmfakecloud (default), qmldiff, dev, all"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "🔨 Compiling reMarkable.dylib (mode: $BUILD_MODE)..."
|
||||
echo "📦 Qt path: $QT_PATH"
|
||||
|
||||
# Create build directories if necessary
|
||||
@@ -17,21 +45,21 @@ cd "$PROJECT_DIR/build"
|
||||
|
||||
# Configure with CMake and compile
|
||||
if [ -d "$QT_PATH" ]; then
|
||||
cmake -DCMAKE_PREFIX_PATH="$QT_PATH" ..
|
||||
cmake -DCMAKE_PREFIX_PATH="$QT_PATH" $CMAKE_OPTIONS ..
|
||||
else
|
||||
echo "⚠️ Qt not found at $QT_PATH, trying without specifying path..."
|
||||
cmake ..
|
||||
cmake $CMAKE_OPTIONS ..
|
||||
fi
|
||||
|
||||
make $APP_NAME
|
||||
make reMarkable
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo ""
|
||||
echo "✅ Compilation successful!"
|
||||
echo "📍 Dylib: $PROJECT_DIR/build/dylibs/$APP_NAME.dylib"
|
||||
echo "📍 Dylib: $PROJECT_DIR/build/dylibs/reMarkable.dylib"
|
||||
echo ""
|
||||
echo "🚀 To inject into the reMarkable application:"
|
||||
echo " DYLD_INSERT_LIBRARIES=\"$PROJECT_DIR/build/dylibs/$APP_NAME.dylib\" /Applications/reMarkable.app/Contents/MacOS/reMarkable"
|
||||
echo " DYLD_INSERT_LIBRARIES=\"$PROJECT_DIR/build/dylibs/reMarkable.dylib\" /Applications/reMarkable.app/Contents/MacOS/reMarkable"
|
||||
echo ""
|
||||
else
|
||||
echo "❌ Compilation failed"
|
||||
|
||||
@@ -63,7 +63,27 @@ mkdir -p "$APP_PATH/Contents/Resources/"
|
||||
cp "$DYLIB" "$APP_PATH/Contents/Resources/"
|
||||
echo "[INFO] Copied $DYLIB to $APP_PATH/Contents/Resources/"
|
||||
|
||||
optool install -c load -p "@executable_path/../Resources/$(basename "$DYLIB")" -t "$EXECUTABLE_PATH"
|
||||
# Use optool from the scripts folder
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
# Copy libzstd dependency and fix the reference in reMarkable.dylib
|
||||
LIBZSTD_PATH="$SCRIPT_DIR/../libs/libzstd.1.dylib"
|
||||
if [ -f "$LIBZSTD_PATH" ]; then
|
||||
cp "$LIBZSTD_PATH" "$APP_PATH/Contents/Resources/"
|
||||
echo "[INFO] Copied libzstd.1.dylib to $APP_PATH/Contents/Resources/"
|
||||
|
||||
# Update the dylib reference to @executable_path/../Resources (handle multiple possible source paths)
|
||||
DYLIB_IN_APP="$APP_PATH/Contents/Resources/$(basename "$DYLIB")"
|
||||
install_name_tool -change "/usr/local/lib/libzstd.1.dylib" "@executable_path/../Resources/libzstd.1.dylib" "$DYLIB_IN_APP"
|
||||
install_name_tool -change "/usr/local/opt/zstd/lib/libzstd.1.dylib" "@executable_path/../Resources/libzstd.1.dylib" "$DYLIB_IN_APP"
|
||||
install_name_tool -change "/opt/homebrew/lib/libzstd.1.dylib" "@executable_path/../Resources/libzstd.1.dylib" "$DYLIB_IN_APP"
|
||||
install_name_tool -change "/opt/homebrew/opt/zstd/lib/libzstd.1.dylib" "@executable_path/../Resources/libzstd.1.dylib" "$DYLIB_IN_APP"
|
||||
echo "[INFO] Updated libzstd references in $(basename "$DYLIB")"
|
||||
else
|
||||
echo "[WARNING] libzstd.1.dylib not found at $LIBZSTD_PATH - app may fail on systems without zstd"
|
||||
fi
|
||||
|
||||
"$SCRIPT_DIR/optool" install -c load -p "@executable_path/../Resources/$(basename "$DYLIB")" -t "$EXECUTABLE_PATH"
|
||||
echo "[INFO] Injected $DYLIB into $EXECUTABLE_PATH"
|
||||
|
||||
sudo codesign --remove-signature "$EXECUTABLE_PATH"
|
||||
|
||||
BIN
scripts/optool
Executable file
BIN
scripts/optool
Executable file
Binary file not shown.
@@ -214,18 +214,21 @@ static inline QString QStringFromNSStringSafe(NSString *string) {
|
||||
reMarkableDylib *dylib = [[reMarkableDylib alloc] init];
|
||||
[dylib hook];
|
||||
|
||||
#ifdef BUILD_MODE_RMFAKECLOUD
|
||||
// Add custom Help menu entry to open config file
|
||||
NSString *configPath = ReMarkableConfigFilePath();
|
||||
NSString *fileURL = [NSString stringWithFormat:@"file://%@", configPath];
|
||||
[MenuActionController addCustomHelpMenuEntry:@"Open rmfakecloud config"
|
||||
withURL:fileURL
|
||||
withDelay:2.0];
|
||||
#endif
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation reMarkableDylib
|
||||
|
||||
#ifdef BUILD_MODE_RMFAKECLOUD
|
||||
static QNetworkReply *(*original_qNetworkAccessManager_createRequest)(
|
||||
QNetworkAccessManager *self,
|
||||
QNetworkAccessManager::Operation op,
|
||||
@@ -235,13 +238,69 @@ static QNetworkReply *(*original_qNetworkAccessManager_createRequest)(
|
||||
static void (*original_qWebSocket_open)(
|
||||
QWebSocket *self,
|
||||
const QNetworkRequest &request) = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_MODE_QMLDIFF
|
||||
static int (*original_qRegisterResourceData)(
|
||||
int,
|
||||
const unsigned char *,
|
||||
const unsigned char *,
|
||||
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 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<NSString *> *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) {
|
||||
if (host.isEmpty()) {
|
||||
return false;
|
||||
@@ -264,10 +323,13 @@ static inline bool shouldPatchURL(const QString &host) {
|
||||
)""")
|
||||
.contains(host, Qt::CaseInsensitive);
|
||||
}
|
||||
#endif
|
||||
|
||||
- (BOOL)hook {
|
||||
NSLogger(@"[reMarkable] Starting hooks...");
|
||||
|
||||
#ifdef BUILD_MODE_RMFAKECLOUD
|
||||
NSLogger(@"[reMarkable] Build mode: rmfakecloud");
|
||||
ReMarkableLoadOrCreateConfig();
|
||||
NSLogger(@"[reMarkable] Using override host %@ and port %@", gConfiguredHost, gConfiguredPort);
|
||||
|
||||
@@ -282,17 +344,44 @@ static inline bool shouldPatchURL(const QString &host) {
|
||||
hookFunction:(void *)hooked_qWebSocket_open
|
||||
originalFunction:(void **)&original_qWebSocket_open
|
||||
logPrefix:@"[reMarkable]"];
|
||||
#endif
|
||||
|
||||
// WIP: Implement resource data registration hooking
|
||||
// [MemoryUtils hookSymbol:@"QtCore"
|
||||
// symbolName:@"__Z21qRegisterResourceDataiPKhS0_S0_"
|
||||
// hookFunction:(void *)hooked_qRegisterResourceData
|
||||
// originalFunction:(void **)&original_qRegisterResourceData
|
||||
// logPrefix:@"[reMarkable]"];
|
||||
#ifdef BUILD_MODE_QMLDIFF
|
||||
NSLogger(@"[reMarkable] Build mode: qmldiff");
|
||||
[MemoryUtils hookSymbol:@"QtCore"
|
||||
symbolName:@"__Z21qRegisterResourceDataiPKhS0_S0_"
|
||||
hookFunction:(void *)hooked_qRegisterResourceData
|
||||
originalFunction:(void **)&original_qRegisterResourceData
|
||||
logPrefix:@"[reMarkable]"];
|
||||
#endif
|
||||
|
||||
#ifdef BUILD_MODE_DEV
|
||||
NSLogger(@"[reMarkable] Build mode: dev/reverse engineering");
|
||||
[MemoryUtils hookSymbol:@"QtCore"
|
||||
symbolName:@"__ZN9QIODevice5writeEPKcx"
|
||||
hookFunction:(void *)hooked_qIODevice_write
|
||||
originalFunction:(void **)&original_qIODevice_write
|
||||
logPrefix:@"[reMarkable]"];
|
||||
|
||||
// Hook function at address 0x10016D520
|
||||
[MemoryUtils hookAddress:@"reMarkable"
|
||||
staticAddress:0x10016D520
|
||||
hookFunction:(void *)hooked_function_at_0x10016D520
|
||||
originalFunction:(void **)&original_function_at_0x10016D520
|
||||
logPrefix:@"[reMarkable]"];
|
||||
|
||||
// Hook function at address 0x1001B6EE0
|
||||
[MemoryUtils hookAddress:@"reMarkable"
|
||||
staticAddress:0x1001B6EE0
|
||||
hookFunction:(void *)hooked_function_at_0x1001B6EE0
|
||||
originalFunction:(void **)&original_function_at_0x1001B6EE0
|
||||
logPrefix:@"[reMarkable]"];
|
||||
#endif
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#ifdef BUILD_MODE_RMFAKECLOUD
|
||||
extern "C" QNetworkReply* hooked_qNetworkAccessManager_createRequest(
|
||||
QNetworkAccessManager* self,
|
||||
QNetworkAccessManager::Operation op,
|
||||
@@ -345,7 +434,9 @@ extern "C" void hooked_qWebSocket_open(
|
||||
|
||||
original_qWebSocket_open(self, req);
|
||||
}
|
||||
#endif // BUILD_MODE_RMFAKECLOUD
|
||||
|
||||
#ifdef BUILD_MODE_QMLDIFF
|
||||
extern "C" int hooked_qRegisterResourceData(
|
||||
int version,
|
||||
const unsigned char *tree,
|
||||
@@ -386,5 +477,108 @@ extern "C" int hooked_qRegisterResourceData(
|
||||
}
|
||||
return status;
|
||||
}
|
||||
#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_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
|
||||
@@ -30,4 +30,20 @@
|
||||
logPrefix:(NSString *)logPrefix
|
||||
delayInSeconds:(NSTimeInterval)delayInSeconds;
|
||||
|
||||
/**
|
||||
* Hooks a function at a specific address after calculating ASLR slide.
|
||||
*
|
||||
* @param imageName The name of the image/library (e.g., "QtNetwork" or "reMarkable").
|
||||
* @param staticAddress The static address from the binary (before ASLR).
|
||||
* @param hookFunction The function to replace the original with.
|
||||
* @param originalFunction Pointer to store the original function address.
|
||||
* @param logPrefix Prefix for log messages (optional, can be nil).
|
||||
* @return YES if the hook was successfully installed, NO otherwise.
|
||||
*/
|
||||
+ (BOOL)hookAddress:(NSString *)imageName
|
||||
staticAddress:(uintptr_t)staticAddress
|
||||
hookFunction:(void *)hookFunction
|
||||
originalFunction:(void **)originalFunction
|
||||
logPrefix:(NSString *)logPrefix;
|
||||
|
||||
@end
|
||||
|
||||
@@ -103,4 +103,37 @@
|
||||
}
|
||||
}
|
||||
|
||||
+ (BOOL)hookAddress:(NSString *)imageName
|
||||
staticAddress:(uintptr_t)staticAddress
|
||||
hookFunction:(void *)hookFunction
|
||||
originalFunction:(void **)originalFunction
|
||||
logPrefix:(NSString *)logPrefix {
|
||||
|
||||
NSLogger(@"%@ Starting hook installation at static address: 0x%lx", logPrefix, staticAddress);
|
||||
|
||||
int imageIndex = [self indexForImageWithName:imageName];
|
||||
if (imageIndex < 0) {
|
||||
NSLogger(@"%@ ERROR: Image %@ not found", logPrefix, imageName);
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Calculate ASLR slide
|
||||
intptr_t slide = _dyld_get_image_vmaddr_slide(imageIndex);
|
||||
NSLogger(@"%@ Image %@ ASLR slide: 0x%lx", logPrefix, imageName, slide);
|
||||
|
||||
// Calculate actual runtime address
|
||||
void *actualAddress = (void *)(staticAddress + slide);
|
||||
NSLogger(@"%@ Calculated runtime address: %p (static: 0x%lx + slide: 0x%lx)", logPrefix, actualAddress, staticAddress, slide);
|
||||
|
||||
int hookResult = tiny_hook(actualAddress, hookFunction, originalFunction);
|
||||
|
||||
if (hookResult == 0) {
|
||||
NSLogger(@"%@ Hook successfully installed at address %p", logPrefix, actualAddress);
|
||||
return YES;
|
||||
} else {
|
||||
NSLogger(@"%@ ERROR: Failed to install hook at address %p (code: %d)", logPrefix, actualAddress, hookResult);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -36,6 +36,7 @@ static NSString *ReMarkableDumpRootDirectory(void) {
|
||||
return dumpDirectory;
|
||||
}
|
||||
|
||||
#ifdef BUILD_MODE_QMLDIFF
|
||||
uint32_t readUInt32(uint8_t *addr, int offset) {
|
||||
return (uint32_t)(addr[offset + 0] << 24) |
|
||||
(uint32_t)(addr[offset + 1] << 16) |
|
||||
@@ -379,3 +380,4 @@ void processNode(struct ResourceRoot *root, int node, const char *rootName) {
|
||||
ReMarkableDumpResourceFile(root, node, rootName ? rootName : "", nameBuffer, fileFlags);
|
||||
}
|
||||
}
|
||||
#endif // BUILD_MODE_QMLDIFF
|
||||
Reference in New Issue
Block a user