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

View File

@@ -76,7 +76,7 @@ static void LoadConfig()
{
gConfiguredPort = obj["port"].toInt();
}
Log("[*] Loaded config: host=" + gConfiguredHost + ", port=" + std::to_string(gConfiguredPort));
return;
}
}
@@ -118,6 +118,8 @@ static inline bool shouldPatchURL(const QString& host)
dev.internal.cloud.remarkable.com
eu.internal.tctn.cloud.remarkable.com
webapp-prod.cloud.remarkable.engineering
vernemq-prod.cloud.remarkable.engineering
vernemq-dev.cloud.remarkable.engineering
)""")
.contains(host, Qt::CaseInsensitive);
}
@@ -144,37 +146,53 @@ QNetworkReply* __fastcall hookedCreateRequest(
const QNetworkRequest& req,
QIODevice* outgoingData)
{
Log("[*] Intercepted createRequest");
const QUrl url = req.url();
const QString host = url.host();
Log("[HTTP] Request to: " + url.toString().toStdString() + " (Method: " + std::to_string((int)op) + ")");
if (shouldPatchURL(host)) {
QNetworkRequest newReq(req);
QUrl newUrl = url;
newUrl.setHost(QString::fromStdString(gConfiguredHost));
newUrl.setPort(gConfiguredPort);
newReq.setUrl(newUrl);
Log("[HTTP PATCHED] " + host.toStdString() + " -> " + newUrl.toString().toStdString());
return originalCreateRequest ? originalCreateRequest(self, op, newReq, outgoingData) : nullptr;
Log("[HTTP PATCHED] " + host.toStdString() + ":" + std::to_string(gConfiguredPort) + " -> " + newUrl.toString().toStdString());
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(
QWebSocket* self,
const QNetworkRequest& req)
{
if (!originalWebSocketOpen) return;
Log("[*] Intercepted QWebSocket::open");
if (!originalWebSocketOpen) {
return;
}
const QUrl url = req.url();
const QString host = url.host();
Log("[WS] Opening: " + url.toString().toStdString());
if (shouldPatchURL(host)) {
QUrl newUrl = url;
newUrl.setHost(QString::fromStdString(gConfiguredHost));
newUrl.setPort(gConfiguredPort);
QNetworkRequest newReq(req);
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);
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)
{
@@ -191,6 +308,7 @@ void* ResolveExport(HMODULE module, const char* 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;
}
@@ -208,6 +326,9 @@ void InstallHooks()
HMODULE qtNetwork = nullptr;
HMODULE qtWebSockets = nullptr;
HMODULE mqttCLib = nullptr;
// HMODULE mqttCppLib = nullptr;
HMODULE mainModule = GetModuleHandleA(NULL);
while (!qtNetwork)
{
@@ -221,7 +342,19 @@ void InstallHooks()
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(
qtNetwork,
@@ -233,14 +366,30 @@ void InstallHooks()
"?open@QWebSocket@@QEAAXAEBVQNetworkRequest@@@Z"
);
if (!createRequestAddr || !webSocketOpenAddr)
{
Log("[ERROR] Failed to resolve one or more symbols");
return;
}
// void* asyncClientCtorAddr = ResolveExport(
// mqttCppLib,
// "??0async_client@mqtt@@QEAA@AEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0PEAViclient_persistence@1@@Z"
// );
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(
createRequestAddr,