From b9c992e3d7a679ff7ee3d977a5f90f657110a8aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=88=9A=28noham=29=C2=B2?= <100566912+NohamR@users.noreply.github.com> Date: Sat, 9 May 2026 23:14:02 +0200 Subject: [PATCH] Implement export forwarders and refactor hooks Introduce a PAHO_FORWARDER_EXPORTS macro and generate Original_* FARPROC forwarder targets, replace the many hand-written fake exports with assembly forwarding stubs, and simplify exports.cpp to declare and initialize those forwarder pointers. Refactor paho-mqtt3as-proxy hook logic: improve logging, robustly load/save JSON config using std::filesystem and safe parsing, consolidate URL/host patching logic for HTTP/WS/MQTT, and add safer MQTT URI patching and resolution helpers. Update main to populate forwarder addresses at startup and make hook installation more defensive when symbols aren't found. Add docs images, update README (bump tested version and enable images), remove STATE.md, and adjust .gitignore to keep docs included. --- .gitignore | 1 - README.md | 4 +- STATE.md | 157 ------- docs/latest.png | Bin 0 -> 278326 bytes docs/rm.png | Bin 0 -> 394300 bytes paho-mqtt3as-proxy/common.h | 58 ++- paho-mqtt3as-proxy/exports.cpp | 58 +-- paho-mqtt3as-proxy/hook.cpp | 631 +++++++++++++++++++--------- paho-mqtt3as-proxy/main.cpp | 4 + paho-mqtt3as-proxy/paho-mqtt3as.asm | 66 ++- scripts/install-hook.ps1 | 23 +- 11 files changed, 581 insertions(+), 421 deletions(-) delete mode 100644 STATE.md create mode 100644 docs/latest.png create mode 100644 docs/rm.png diff --git a/.gitignore b/.gitignore index dbcea13..e42cfa2 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,4 @@ /paho-mqtt3as-proxy/x64 /x64 .DS_Store -/docs /src diff --git a/README.md b/README.md index ea752c0..c9e6ff8 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,12 @@ RMHook-Win intercepts the reMarkable Desktop app's Qt networking layer and patch ## Compatibility **Tested and working on:** - +
## Installation and usage diff --git a/STATE.md b/STATE.md deleted file mode 100644 index 3dafd61..0000000 --- a/STATE.md +++ /dev/null @@ -1,157 +0,0 @@ -Without hook - -[*] Loaded config: host=rm.noh.am, port=443 -[*] Initializing MinHook -[+] Qt and MQTT DLLs loaded -[+] Resolved ?createRequest@QNetworkAccessManager@@MEAAPEAVQNetworkReply@@W4Operation@1@AEBVQNetworkRequest@@PEAVQIODevice@@@Z at 140718018555616 -[+] Resolved ?open@QWebSocket@@QEAAXAEBVQNetworkRequest@@@Z at 140718986708784 -[+] Hooked createRequest -[+] Hooked QWebSocket::open -[+] Hooks enabled - - -(4d8.23e4): Access violation - code c0000005 (first chance) -First chance exceptions are reported before any exception handling. -This exception may be expected and handled. -ucrtbase!#strlen: -00007ffb`f6a9d040 38400402 ldrb w2,[x0],#0 - - -[0x0] ucrtbase!#strlen 0x885a3fb920 0x7ffbf6a9d00c -[0x1] ucrtbase!#strlen_entry_thunk+0xc 0x885a3fb920 0x7ffb784faab6 -[0x2] paho_mqttpp3!mqtt::exception::error_str+0x56 0x885a3fb930 0x7ffb784f5bad -[0x3] paho_mqttpp3!mqtt::exception::exception+0x2d 0x885a3fb9d0 0x7ffb784f54ef -[0x4] paho_mqttpp3!mqtt::async_client::async_client+0x29f 0x885a3fba40 0x7ffb784f582d -[0x5] paho_mqttpp3!mqtt::async_client::async_client+0x5d 0x885a3fbb10 0x7ff764ce0100 -[0x6] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xf1fcf 0x885a3fbba0 0x7ff764cdb066 -[0x7] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xecf35 0x885a3fbcd0 0x7ff764c6a51a -[0x8] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0x7c3e9 0x885a3fbd10 0x7ff764ca14f5 -[0x9] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xb33c4 0x885a3fbd50 0x7ff764c90318 -[0xa] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xa21e7 0x885a3fbe30 0x7ff764cbcaac -[0xb] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xce97b 0x885a3fbe90 0x7ff764cbbf0a -[0xc] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xcddd9 0x885a3fbf60 0x7ffb2a0f1a51 -[0xd] Qt6Core!QObject::qt_static_metacall+0x1451 0x885a3fbfe0 0x7ffb2a0f4564 -[0xe] Qt6Core!QMetaObject::activate+0x84 0x885a3fc110 0x7ff764c99964 -[0xf] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xab833 0x885a3fc140 0x7ffb2a0fda9b -[0x10] Qt6Core!QMetaCallEvent::placeMetaCall+0x3b 0x885a3fc170 0x7ffb2a0fb8d2 -[0x11] Qt6Core!QObject::event+0x182 0x885a3fc1b0 0x7ffb2a0b301b -[0x12] Qt6Core!QCoreApplication::notify+0xbb 0x885a3fc2c0 0x7ffb2a0b313f -[0x13] Qt6Core!QCoreApplication::notifyInternal2+0x10f 0x885a3fc310 0x7ffb2a0b584c -[0x14] Qt6Core!QCoreApplicationPrivate::sendPostedEvents+0x1fc 0x885a3fc380 0x7ffb2a23eb70 -[0x15] Qt6Core!QEventDispatcherWin32::processEvents+0x90 0x885a3fc470 0x7ffb2a0b9c44 -[0x16] Qt6Core!QEventLoop::exec+0x1c4 0x885a3ff5d0 0x7ffb2a19d90f -[0x17] Qt6Core!QThread::exec+0x16f 0x885a3ff670 0x7ffb2a245e29 -[0x18] Qt6Core!QThread::start+0x579 0x885a3ff6e0 0x7ffbfa0809fc -[0x19] KERNEL32!$iexit_thunk$cdecl$i8$i8+0x1c 0x885a3ff780 0x7ffbfa017bb0 -[0x1a] KERNEL32!#BaseThreadInitThunk+0x30 0x885a3ff7b0 0x7ffbfb67c4c8 -[0x1b] ntdll!#RtlUserThreadStart+0x48 0x885a3ff7c0 0x0 - - - - -With MQTTAsync_createWithOptions from paho-mqtt3as_orig.dll hook to return patched url - -[*] Loaded config: host=rm.noh.am, port=443 -[*] Initializing MinHook -[+] Qt and MQTT DLLs loaded -[+] Resolved ?createRequest@QNetworkAccessManager@@MEAAPEAVQNetworkReply@@W4Operation@1@AEBVQNetworkRequest@@PEAVQIODevice@@@Z at 140718030679776 -[+] Resolved ?open@QWebSocket@@QEAAXAEBVQNetworkRequest@@@Z at 140718986643248 -[+] Resolved MQTTAsync_createWithOptions at 140718859938896 -[+] Hooked MQTTAsync_createWithOptions -[+] Hooked createRequest -[+] Hooked QWebSocket::open -[+] Hooks enabled - - - -(1184.1c88): Access violation - code c0000005 (first chance) -First chance exceptions are reported before any exception handling. -This exception may be expected and handled. -ucrtbase!#strlen: -00007ffb`f6a9d040 38400402 ldrb w2,[x0],#0 - - -[0x0] ucrtbase!#strlen 0x70df7fc050 0x7ffbf6a9d00c -[0x1] ucrtbase!#strlen_entry_thunk+0xc 0x70df7fc050 0x7ffb7b1daab6 -[0x2] paho_mqttpp3!mqtt::exception::error_str+0x56 0x70df7fc060 0x7ffb7b1d5bad -[0x3] paho_mqttpp3!mqtt::exception::exception+0x2d 0x70df7fc100 0x7ffb7b1d54ef -[0x4] paho_mqttpp3!mqtt::async_client::async_client+0x29f 0x70df7fc170 0x7ffb7b1d582d -[0x5] paho_mqttpp3!mqtt::async_client::async_client+0x5d 0x70df7fc240 0x7ff764ce0100 -[0x6] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xf1fcf 0x70df7fc2d0 0x7ff764cdb066 -[0x7] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xecf35 0x70df7fc400 0x7ff764c6a51a -[0x8] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0x7c3e9 0x70df7fc440 0x7ff764ca14f5 -[0x9] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xb33c4 0x70df7fc480 0x7ff764c90318 -[0xa] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xa21e7 0x70df7fc560 0x7ff764cbcaac -[0xb] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xce97b 0x70df7fc5c0 0x7ff764cbbf0a -[0xc] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xcddd9 0x70df7fc690 0x7ffb29b81a51 -[0xd] Qt6Core!QObject::qt_static_metacall+0x1451 0x70df7fc710 0x7ffb29b84564 -[0xe] Qt6Core!QMetaObject::activate+0x84 0x70df7fc840 0x7ff764c99964 -[0xf] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xab833 0x70df7fc870 0x7ffb29b8da9b -[0x10] Qt6Core!QMetaCallEvent::placeMetaCall+0x3b 0x70df7fc8a0 0x7ffb29b8b8d2 -[0x11] Qt6Core!QObject::event+0x182 0x70df7fc8e0 0x7ffb29b4301b -[0x12] Qt6Core!QCoreApplication::notify+0xbb 0x70df7fc9f0 0x7ffb29b4313f -[0x13] Qt6Core!QCoreApplication::notifyInternal2+0x10f 0x70df7fca40 0x7ffb29b4584c -[0x14] Qt6Core!QCoreApplicationPrivate::sendPostedEvents+0x1fc 0x70df7fcab0 0x7ffb29cceb70 -[0x15] Qt6Core!QEventDispatcherWin32::processEvents+0x90 0x70df7fcba0 0x7ffb29b49c44 -[0x16] Qt6Core!QEventLoop::exec+0x1c4 0x70df7ffd00 0x7ffb29c2d90f -[0x17] Qt6Core!QThread::exec+0x16f 0x70df7ffda0 0x7ffb29cd5e29 -[0x18] Qt6Core!QThread::start+0x579 0x70df7ffe10 0x7ffbfa0809fc -[0x19] KERNEL32!$iexit_thunk$cdecl$i8$i8+0x1c 0x70df7ffeb0 0x7ffbfa017bb0 -[0x1a] KERNEL32!#BaseThreadInitThunk+0x30 0x70df7ffee0 0x7ffbfb67c4c8 -[0x1b] ntdll!#RtlUserThreadStart+0x48 0x70df7ffef0 0x0 - - -With MQTTAsync_createWithOptions from paho-mqtt3as.dll hook to return patched url - -[*] Loaded config: host=rm.noh.am, port=443 -[*] Initializing MinHook -[+] Qt and MQTT DLLs loaded -[+] Resolved ?createRequest@QNetworkAccessManager@@MEAAPEAVQNetworkReply@@W4Operation@1@AEBVQNetworkRequest@@PEAVQIODevice@@@Z at 140718064627424 -[+] Resolved ?open@QWebSocket@@QEAAXAEBVQNetworkRequest@@@Z at 140719255209776 -[+] Resolved MQTTAsync_createWithOptions at 140719258086256 -[+] Hooked MQTTAsync_createWithOptions -[+] Hooked createRequest -[+] Hooked QWebSocket::open -[+] Hooks enabled -[MQTT] MQTTAsync_createWithOptions URI: ssl://vernemq-prod.cloud.remarkable.engineering:443 ClientId: noham-ccd226f9-4f37-4c45-a6ee-22f21f5e7548 PersistenceType: 1 -[MQTT] originalMQTTAsyncCreate returned -1050472512 Final URI: ssl://rm.noh.am:443 - - -(538.14bc): Access violation - code c0000005 (first chance) -First chance exceptions are reported before any exception handling. -This exception may be expected and handled. -ucrtbase!#strlen: -00007ffb`f6a9d040 38400402 ldrb w2,[x0],#0 - - -[0x0] ucrtbase!#strlen 0x86d71fbcb0 0x7ffbf6a9d00c -[0x1] ucrtbase!#strlen_entry_thunk+0xc 0x86d71fbcb0 0x7ffbc1649348 -[0x2] paho_mqtt3as!std::_Narrow_char_traitsN4s*Dms}EpOBj{U}0flU@>Q@V7V1_jpYu@rNpqquW29k@h>tXKGhOw
z@wM-2BfZ~wN1jIL6wZ&3t`{GZTwM1P#NNhoV87khA2&)U=O4=`H_D&Q_BA@X7SjIx
z^&4h=Ce=^SZl!KjwHOA~0kz1&dn0LuFY~>gY=yl-Na_2RdRKe5oI-bg&!K7%o3WnG
zp6|S#$VPhAZe@)5_I9QwKjYBvHSPTMQ@&$+?B3?w=AoB|=YS`C#ASMCa(vWdTx%@7
z*dYJyi}Hl`70!kMuQ;6UZ4qtBZZ)@j1R6j}Tc5R><12BjA ndyQ5f<4?JnOg5$!mQ;sORJi3EbQ;a`x
z=2Vud6Mea-Ld@dH2BkHziRVtq{2Pt5W=i9#C5z@m)%;U8`-|F67Rcu3&NjysU_@}n
zU|2)!v(p0y+wcSc% JVZDKaFhhI$1&~|2gOW?Iu9p0L)p;r|hfDl2`dm`I)B$Zg^dWBB_UcSmQ}D
z0F5N`2Beu|R~|(3O*2=0NM!0T3-(EsG*_wFX4yKBXx136%Q)>-E5P(H-0~^vKlbwf
zF~G_H8C`;KSBN2MFBZR?Ub8jIM8JModjH`s!%}K2*dAQDy)yS^^Nf2gv8QQ`3+o=*
z60;T#7Rke%th>?w!IFQyPyhVLe`*^Qb~PxwK(g*-^JUJAe52sL;zF_tjgU7jaKCYv
zqpepfk`zXtsRnAoPwf{`BM+b9YHp3&UPAT=!S`ifkE;HrO7@={{r`0phdNAt())LP
zxJpm{g27hgHnD{~Ln$%QL{qMH$kI6K8(M#MH0nb;mZw$E49WHKgDn@8cP?z0pR_O(
zf(cm?Ji!SrLJR*Jb=dV{8VC9-gjqEW-_!DJL#5*$CYuP#=u~7HTyd9tV93Iokmk8R
zu-23H;!*i~d7!lH?J~@sM;mr;?h%)rDS!yW&j0T9u)>s5ylQK;+X+$ziB6+krg)Ch
zi8ng>g<7GM3XF%gyn78`VOIoj8?hO253^1Ww#~fi8_R*f{bfx;KH?ie>|jF?szQ$P
z=qZ_T**UujoYN7|pR^qa$EFs(QikExX4X{X->bL%7c@YY;1vk?wwHtNz<(JUa)~iR
zPyBmj8j&CiR~j2nPgU8_Uq0VaNhPQs*}dE+O^IZ{nD}YG=s9Yt-->iNC;RoF&`8?<
zzgr36?E#|eYcC%LAOy7xw6(pQC!4Q<|IiJZh9Hjk8(m!u6BO
z;BhLa^~Va)ikB5JE8X2gALUq)pAamqayTz#i}wD|`H$Wo`#Y!Zs_7Z)xs0W+X0J;2
zWzzRN%aA)zj(8q%H=jQ#F)gt{yv9v$Kkp==VeHrV)3GveZKk}(A(~%J|FD29vp@A=
zs-H+^Y*t2#95$EBSXXd;VA0OGfBnv3C~GKEl{m*M$F-u|C+b|Y!0m6^V4+cqkyBMe
z6}D=i%KxssX8x+Jj^XfBhIIXCeIxYpDE{d5Z^F^|QH+LHUj5kk__M;Hj45u9#H3!?
zLVqv>)NH`Py-=)pJK>J@wT3sj3kB8sfw@hPbpykf=iX{#pF+fI?4H`y4nb3EoTn0U
zVsrNFR;u1tnV?dUMvqZA)7@V#N3p)lN5&|VVTgRIlhXRTwD%M5>#5=V-u&kJnCYBV
z)uBjj24O?Ye)@>p=2Ho+)qB#(=K`}0w;>OW=31P8RYnZ}QzD+ig*^Bl318Nk)?rX?
zJ%J_%F8GMSJ3EgQUbz~nn%*<>g4N(R(ejVV571m
zQM
NCDoSW=ktW%67SNj|sxyTz*`oTLuODRk}o}=HfkY-d}Y{CId`Y3)nPl@raiLc=F
z7g}Oie2VLFTP{dGe}bWDBCyo^{`=#fAz>9@`23!^`2L8ODDF2JAY_~
Mhz
zFZ>14i58br%0H@3n&Y-E)asg?px6G=Uqk_FxJ9>*(8q{O_yZ
zczySk2Br^}>)Ud%kLBocQ1J$88ZvE2>uR^6y5FbiUBX5=mJwYDs}=1bx(yXXf$Rra
zzS7XO?--wu4Ab93r|ez{Up2T#7VBsw^#n
zEvRQ291*s5iN#i6lWCI0j=v}FLSrLB@cfdwr!jH#EZ$W_x<*?40wp
DpXG7Q~EBH;d*DmeL?-)%oxvc^$