Add MQTT URI patching and verbose hook logs

This commit is contained in:
√(noham)²
2026-05-09 22:11:08 +02:00
parent cf97924b98
commit 544caf14a7
2 changed files with 319 additions and 13 deletions

157
STATE.md Normal file
View File

@@ -0,0 +1,157 @@
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_traits<char,int>::length+0x8 (Inline Function) (Inline Function)
[0x3] paho_mqtt3as!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::{ctor}+0x14 (Inline Function) (Inline Function)
[0x4] paho_mqtt3as!hookedMQTTAsyncCreate+0x88 0x86d71fbcc0 0x7ffba6a1aa95
[0x5] paho_mqttpp3!mqtt::exception::error_str+0x35 0x86d71fbe80 0x7ffba6a15bad
[0x6] paho_mqttpp3!mqtt::exception::exception+0x2d 0x86d71fbf20 0x7ffba6a154ef
[0x7] paho_mqttpp3!mqtt::async_client::async_client+0x29f 0x86d71fbf90 0x7ffba6a1582d
[0x8] paho_mqttpp3!mqtt::async_client::async_client+0x5d 0x86d71fc060 0x7ff764ce0100
[0x9] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xf1fcf 0x86d71fc0f0 0x7ff764cdb066
[0xa] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xecf35 0x86d71fc220 0x7ff764c6a51a
[0xb] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0x7c3e9 0x86d71fc260 0x7ff764ca14f5
[0xc] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xb33c4 0x86d71fc2a0 0x7ff764c90318
[0xd] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xa21e7 0x86d71fc380 0x7ff764cbcaac
[0xe] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xce97b 0x86d71fc3e0 0x7ff764cbbf0a
[0xf] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xcddd9 0x86d71fc4b0 0x7ffb29271a51
[0x10] Qt6Core!QObject::qt_static_metacall+0x1451 0x86d71fc530 0x7ffb29274564
[0x11] Qt6Core!QMetaObject::activate+0x84 0x86d71fc660 0x7ff764c99964
[0x12] reMarkable!rtc::Description::Entry::ExtMap::ExtMap+0xab833 0x86d71fc690 0x7ffb2927da9b
[0x13] Qt6Core!QMetaCallEvent::placeMetaCall+0x3b 0x86d71fc6c0 0x7ffb2927b8d2
[0x14] Qt6Core!QObject::event+0x182 0x86d71fc700 0x7ffb2923301b
[0x15] Qt6Core!QCoreApplication::notify+0xbb 0x86d71fc810 0x7ffb2923313f
[0x16] Qt6Core!QCoreApplication::notifyInternal2+0x10f 0x86d71fc860 0x7ffb2923584c
[0x17] Qt6Core!QCoreApplicationPrivate::sendPostedEvents+0x1fc 0x86d71fc8d0 0x7ffb293beb70
[0x18] Qt6Core!QEventDispatcherWin32::processEvents+0x90 0x86d71fc9c0 0x7ffb29239c44
[0x19] Qt6Core!QEventLoop::exec+0x1c4 0x86d71ffb20 0x7ffb2931d90f
[0x1a] Qt6Core!QThread::exec+0x16f 0x86d71ffbc0 0x7ffb293c5e29
[0x1b] Qt6Core!QThread::start+0x579 0x86d71ffc30 0x7ffbfa0809fc
[0x1c] KERNEL32!$iexit_thunk$cdecl$i8$i8+0x1c 0x86d71ffcd0 0x7ffbfa017bb0
[0x1d] KERNEL32!#BaseThreadInitThunk+0x30 0x86d71ffd00 0x7ffbfb67c4c8
[0x1e] ntdll!#RtlUserThreadStart+0x48 0x86d71ffd10 0x0

View File

@@ -76,7 +76,7 @@ static void LoadConfig()
{ {
gConfiguredPort = obj["port"].toInt(); gConfiguredPort = obj["port"].toInt();
} }
Log("[*] Loaded config: host=" + gConfiguredHost + ", port=" + std::to_string(gConfiguredPort));
return; return;
} }
} }
@@ -118,6 +118,8 @@ static inline bool shouldPatchURL(const QString& host)
dev.internal.cloud.remarkable.com dev.internal.cloud.remarkable.com
eu.internal.tctn.cloud.remarkable.com eu.internal.tctn.cloud.remarkable.com
webapp-prod.cloud.remarkable.engineering webapp-prod.cloud.remarkable.engineering
vernemq-prod.cloud.remarkable.engineering
vernemq-dev.cloud.remarkable.engineering
)""") )""")
.contains(host, Qt::CaseInsensitive); .contains(host, Qt::CaseInsensitive);
} }
@@ -144,37 +146,53 @@ QNetworkReply* __fastcall hookedCreateRequest(
const QNetworkRequest& req, const QNetworkRequest& req,
QIODevice* outgoingData) QIODevice* outgoingData)
{ {
Log("[*] Intercepted createRequest");
const QUrl url = req.url(); const QUrl url = req.url();
const QString host = url.host(); const QString host = url.host();
Log("[HTTP] Request to: " + url.toString().toStdString() + " (Method: " + std::to_string((int)op) + ")");
if (shouldPatchURL(host)) { if (shouldPatchURL(host)) {
QNetworkRequest newReq(req); QNetworkRequest newReq(req);
QUrl newUrl = url; QUrl newUrl = url;
newUrl.setHost(QString::fromStdString(gConfiguredHost)); newUrl.setHost(QString::fromStdString(gConfiguredHost));
newUrl.setPort(gConfiguredPort); newUrl.setPort(gConfiguredPort);
newReq.setUrl(newUrl); newReq.setUrl(newUrl);
Log("[HTTP PATCHED] " + host.toStdString() + " -> " + newUrl.toString().toStdString()); Log("[HTTP PATCHED] " + host.toStdString() + ":" + std::to_string(gConfiguredPort) + " -> " + newUrl.toString().toStdString());
return originalCreateRequest ? originalCreateRequest(self, op, newReq, outgoingData) : nullptr; if (originalCreateRequest) {
return originalCreateRequest(self, op, newReq, outgoingData);
}
return nullptr;
} }
return originalCreateRequest ? originalCreateRequest(self, op, req, outgoingData) : nullptr;
if (originalCreateRequest) {
return originalCreateRequest(self, op, req, outgoingData);
}
return nullptr;
} }
void __fastcall hookedWebSocketOpen( void __fastcall hookedWebSocketOpen(
QWebSocket* self, QWebSocket* self,
const QNetworkRequest& req) const QNetworkRequest& req)
{ {
if (!originalWebSocketOpen) return; Log("[*] Intercepted QWebSocket::open");
if (!originalWebSocketOpen) {
return;
}
const QUrl url = req.url(); const QUrl url = req.url();
const QString host = url.host(); const QString host = url.host();
Log("[WS] Opening: " + url.toString().toStdString());
if (shouldPatchURL(host)) { if (shouldPatchURL(host)) {
QUrl newUrl = url; QUrl newUrl = url;
newUrl.setHost(QString::fromStdString(gConfiguredHost)); newUrl.setHost(QString::fromStdString(gConfiguredHost));
newUrl.setPort(gConfiguredPort); newUrl.setPort(gConfiguredPort);
QNetworkRequest newReq(req); QNetworkRequest newReq(req);
newReq.setUrl(newUrl); newReq.setUrl(newUrl);
Log("[WS PATCHED] " + host.toStdString() + " -> " + newUrl.toString().toStdString()); Log("[WS PATCHED] " + host.toStdString() + ":" + std::to_string(gConfiguredPort) + " -> " + newUrl.toString().toStdString());
originalWebSocketOpen(self, newReq); originalWebSocketOpen(self, newReq);
return; return;
} }
@@ -182,6 +200,105 @@ void __fastcall hookedWebSocketOpen(
} }
typedef int(__cdecl* MQTTAsync_createWithOptions_t)(
void** handle,
const char* serverURI,
const char* clientId,
int persistence_type,
void* persistence_context,
void* options
);
static MQTTAsync_createWithOptions_t originalMQTTAsyncCreate = nullptr;
// typedef void* (__fastcall* async_client_ctor_t)(void* self, void* serverURI, void* clientId, void* persistence);
// static async_client_ctor_t originalAsyncClientCtor = nullptr;
// void* __fastcall hookedAsyncClientCtor(void* self, void* serverURI, void* clientId, void* persistence)
// {
// Log("[MQTT] Intercepted mqtt::async_client constructor");
// return self;
// }
// Patch a paho URI: "ssl://host.remarkable.com:port" -> "ssl://proxy:port"
// Returns patched string, or empty if no patch needed.
static std::string PatchMqttUri(const char* uri)
{
if (!uri) return {};
const std::string original(uri);
size_t schemeEnd = original.find("://");
size_t hostStart = (schemeEnd != std::string::npos) ? schemeEnd + 3 : 0;
size_t hostEnd = original.find_first_of(":/", hostStart);
if (hostEnd == std::string::npos) hostEnd = original.size();
const std::string origHost = original.substr(hostStart, hostEnd - hostStart);
// Match any *.remarkable.com or *.remarkable.engineering host
static const char* kSuffixes[] = {
".remarkable.com",
".remarkable.engineering",
nullptr
};
bool shouldPatch = false;
for (int i = 0; kSuffixes[i]; ++i)
{
const std::string suffix(kSuffixes[i]);
if (origHost.size() >= suffix.size() &&
origHost.compare(origHost.size() - suffix.size(),
suffix.size(), suffix) == 0)
{
shouldPatch = true;
break;
}
}
if (!shouldPatch) return {};
std::string patched = original;
patched.replace(hostStart, hostEnd - hostStart, gConfiguredHost);
// Fix port
size_t colonPos = patched.find(':', hostStart + gConfiguredHost.size());
if (colonPos != std::string::npos)
{
size_t numEnd = patched.find_first_not_of("0123456789", colonPos + 1);
if (numEnd == std::string::npos) numEnd = patched.size();
patched.replace(colonPos + 1, numEnd - colonPos - 1,
std::to_string(gConfiguredPort));
}
return patched;
}
int __cdecl hookedMQTTAsyncCreate(
void** handle,
const char* serverURI,
const char* clientId,
int persistence_type,
void* persistence_context,
void* options)
{
Log("[MQTT] MQTTAsync_createWithOptions URI: " + std::string(serverURI ? serverURI : "(null)") + " ClientId: " + (clientId ? clientId : "(null)") + " PersistenceType: " + std::to_string(persistence_type));
const char* finalUri = serverURI;
std::string patched;
patched = PatchMqttUri(serverURI);
if (!patched.empty())
{
finalUri = patched.c_str();
}
int ret = originalMQTTAsyncCreate(
handle,
finalUri,
clientId,
persistence_type,
persistence_context,
options
);
Log("[MQTT] originalMQTTAsyncCreate returned " + std::to_string(ret) + " Final URI: " + std::string(finalUri));
return ret;
// return -1; // Return error to prevent actual MQTT connection attempts until we implement the full patch.
}
void* ResolveExport(HMODULE module, const char* symbol) void* ResolveExport(HMODULE module, const char* symbol)
{ {
@@ -191,6 +308,7 @@ void* ResolveExport(HMODULE module, const char* symbol)
{ {
Log(std::string("[ERROR] Failed to resolve symbol: ") + symbol); Log(std::string("[ERROR] Failed to resolve symbol: ") + symbol);
} }
Log(std::string("[+] Resolved ") + symbol + " at " + std::to_string(reinterpret_cast<uintptr_t>(addr)));
return addr; return addr;
} }
@@ -208,6 +326,9 @@ void InstallHooks()
HMODULE qtNetwork = nullptr; HMODULE qtNetwork = nullptr;
HMODULE qtWebSockets = nullptr; HMODULE qtWebSockets = nullptr;
HMODULE mqttCLib = nullptr;
// HMODULE mqttCppLib = nullptr;
HMODULE mainModule = GetModuleHandleA(NULL);
while (!qtNetwork) while (!qtNetwork)
{ {
@@ -221,7 +342,19 @@ void InstallHooks()
Sleep(100); Sleep(100);
} }
Log("[+] Qt DLLs loaded"); while (!mqttCLib)
{
mqttCLib = GetModuleHandleA("paho-mqtt3as.dll");
Sleep(100);
}
// while (!mqttCppLib)
// {
// mqttCppLib = GetModuleHandleA("paho-mqttpp3.dll");
// Sleep(100);
// }
Log("[+] Qt and MQTT DLLs loaded");
void* createRequestAddr = ResolveExport( void* createRequestAddr = ResolveExport(
qtNetwork, qtNetwork,
@@ -233,14 +366,30 @@ void InstallHooks()
"?open@QWebSocket@@QEAAXAEBVQNetworkRequest@@@Z" "?open@QWebSocket@@QEAAXAEBVQNetworkRequest@@@Z"
); );
if (!createRequestAddr || !webSocketOpenAddr) // void* asyncClientCtorAddr = ResolveExport(
{ // mqttCppLib,
Log("[ERROR] Failed to resolve one or more symbols"); // "??0async_client@mqtt@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0PEAViclient_persistence@1@@Z"
return; // );
}
Log("[+] Symbols resolved"); // if (MH_CreateHook(
// asyncClientCtorAddr,
// &hookedAsyncClientCtor,
// reinterpret_cast<void**>(&originalAsyncClientCtor)
// ) != MH_OK)
// Log("[ERROR] Failed to hook mqtt::async_client constructor");
// else
// Log("[+] Hooked mqtt::async_client constructor");
// void* mqttCreateAddr = ResolveExport(mqttCLib, "MQTTAsync_createWithOptions");
// if (MH_CreateHook(
// mqttCreateAddr,
// &hookedMQTTAsyncCreate,
// reinterpret_cast<void**>(&originalMQTTAsyncCreate)
// ) != MH_OK)
// Log("[ERROR] Failed to hook MQTTAsync_createWithOptions");
// else
// Log("[+] Hooked MQTTAsync_createWithOptions");
if (MH_CreateHook( if (MH_CreateHook(
createRequestAddr, createRequestAddr,