mirror of
https://github.com/NohamR/RMHook.git
synced 2026-01-09 05:58:12 +00:00
Add build modes and dev hooks, improve injection and docs
Introduces build mode options (rmfakecloud, qmldiff, dev, all) to CMake and build scripts, enabling selective compilation of hooks for cloud redirection, Qt resource hooking, and reverse engineering. Adds new hooks and memory logging for dev mode, updates injection script to handle libzstd.1.dylib dependency, and documents build modes in README.
This commit is contained in:
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"}
|
||||
|
||||
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