rmfakecloud icon indicating copy to clipboard operation
rmfakecloud copied to clipboard

Mobile app support

Open Joedmin opened this issue 4 months ago • 13 comments

Hello,

do you think it would be possible to get the official app working with rmfakecloud?

I tried running strings on it's .apk and found it's not using the my.remarkable.com URL directly and it relies on tokens and cookies from the Web login.

I'm thinking of trying modifying the latest 3.20.x app version but I'm not sure it it's possible.

Joedmin avatar Sep 09 '25 16:09 Joedmin

I've noticed that there's issue https://github.com/ddvk/rmfakecloud-proxy/issues/5 that might be somewhat related

Joedmin avatar Sep 09 '25 17:09 Joedmin

It appears most of the Android apps logic is handled within shared libraries. These libraries do contain strings like [*].tectonic.remarkable.com, you probably have to patch those...

lynatic1337 avatar Sep 10 '25 08:09 lynatic1337

you can actually avoid needing to patch rm's libraries every version by modifying libQt6Network_arm64-v8a.so to override the default cert store. just build qt 6.8.2 for android using NDK v26.1.10909125, modify QSslSocketPrivate::setDefaultCaCertificates in qtbase/src/network/ssl/qsslsocket.cpp to load your custom ca, and replace libQt6Network_arm64-v8a.so with the version you just built and it should work with rmfakecloud just fine. i've been doing this since v3.18 and it's also working fine in 3.20. (that being said, i haven't actually tested v3.20's login as i upgraded from 3.18)

er-azh avatar Sep 10 '25 14:09 er-azh

you can actually avoid needing to patch rm's libraries every version by modifying libQt6Network_arm64-v8a.so to override the default cert store. just build qt 6.8.2 for android using NDK v26.1.10909125, modify QSslSocketPrivate::setDefaultCaCertificates in qtbase/src/network/ssl/qsslsocket.cpp to load your custom ca, and replace libQt6Network_arm64-v8a.so with the version you just built and it should work with rmfakecloud just fine. i've been doing this since v3.18 and it's also working fine in 3.20. (that being said, i haven't actually tested v3.20's login as i upgraded from 3.18)

This requires the proxy to be always running tho, right?

lynatic1337 avatar Sep 10 '25 14:09 lynatic1337

you can actually avoid needing to patch rm's libraries every version by modifying libQt6Network_arm64-v8a.so to override the default cert store. just build qt 6.8.2 for android using NDK v26.1.10909125, modify QSslSocketPrivate::setDefaultCaCertificates in qtbase/src/network/ssl/qsslsocket.cpp to load your custom ca, and replace libQt6Network_arm64-v8a.so with the version you just built and it should work with rmfakecloud just fine. i've been doing this since v3.18 and it's also working fine in 3.20. (that being said, i haven't actually tested v3.20's login as i upgraded from 3.18)

Thanks, I'll take a look on it and report back

Joedmin avatar Sep 10 '25 14:09 Joedmin

This requires the proxy to be always running tho, right?

rmfakecloud needs to be always running. you'll also need to add dns records to point to rmfakecloud in your dns server. i don't personally use a proxy though. not sure how it'd affect your setup. (but i guess it needs to be running if you point the dns reconds to it)

er-azh avatar Sep 10 '25 14:09 er-azh

I want to have a somewhat universal solution for this. I have a rooted phone, so changing DNS records wouldn't be an issue, but still

Joedmin avatar Sep 10 '25 14:09 Joedmin

I want to have a somewhat universal solution for this. I have a rooted phone, so changing DNS records wouldn't be an issue, but still

not sure how hard would it be to modify qt's hostname resolution, but that could be a solution. i didn't look into it since i already had the custom records as part of my rmfakecloud setup. and you don't need a rooted phone. any custom/self-hosted dns server would work.

er-azh avatar Sep 10 '25 15:09 er-azh

I'd love to be able to just replace all of the domain strings for mine instance. I think that would be the easiest method to do so.

If that's possible, I'd then try to automate that using some custom written tool so it's easier for others to use

Joedmin avatar Sep 10 '25 15:09 Joedmin

@er-azh okay, I'm stuck at the login as I need to have a user token :/ I replaced the my.remarkable.com URL for mine (had to create another one to match the original length, otherwise the app's view got killed and only whitecreen stayed).

~~The problem is there's not callback in the rmfakecloud prepared for this - ie the my.domain.com/#mobile~~

Now, after changing the loginUrl, the Log in button opens the configured rmfake instance. However, after entering the code, the app gets stuck at this: IMG_20250916_174221.jpg

I'll try to fix this now

Joedmin avatar Sep 16 '25 12:09 Joedmin

@er-azh could you please describe how did you make the app work? I'm not sure if I follow

Joedmin avatar Sep 21 '25 19:09 Joedmin

@Joedmin you are most likely failing the tls handshake since your rmfakecloud server's cert is not trusted, either your libQt6Network modification didn't work or you didn't do it. you can potentially check it with a packet capture. see if any of your tls connections are ending prematurely with a tls alert. and again, i'd advise against modifying strings in the binaries. it's very fragile and will change every version.

as for my dns setup, i've created an A record for rmfakecloud.internal pointing to my rmfakecloud server and then i did:

hwr-production-dot-remarkable-production.appspot.com.	IN	CNAME	rmfakecloud.internal.
service-manager-production-dot-remarkable-production.appspot.com.	IN	CNAME	rmfakecloud.internal.
local.appspot.com.	IN	CNAME	rmfakecloud.internal.
my.remarkable.com.	IN	CNAME	rmfakecloud.internal.
ping.remarkable.com.	IN	CNAME	rmfakecloud.internal.
internal.cloud.remarkable.com.	IN	CNAME	rmfakecloud.internal.
backtrace-proxy.cloud.remarkable.engineering.	IN	CNAME	rmfakecloud.internal.
dev.ping.remarkable.com.	IN	CNAME	rmfakecloud.internal.
dev.tectonic.remarkable.com.	IN	CNAME	rmfakecloud.internal.
dev.internal.cloud.remarkable.com.	IN	CNAME	rmfakecloud.internal.

on my dns server.

i've already explained how to change libQt6Network to trust your rmfakecloud server's cert in https://github.com/ddvk/rmfakecloud/issues/381#issuecomment-32752313020. and as for my modification, here's the exact change i made to qsslsocket.cpp (janky but it works):

void QSslSocketPrivate::setDefaultCaCertificates(const QList<QSslCertificate> &certs)
{

    const char* customCaPemData = "-----BEGIN CERTIFICATE-----...my ca here...-----END CERTIFICATE-----\n";
    QByteArray caCertData = customCaPemData;
    QList<QSslCertificate> customCerts = QSslCertificate::fromData(caCertData, QSsl::Pem);
    if (customCerts.isEmpty()) {
         fprintf(stderr, "ca load failed!\n");
    }

    QSslSocketPrivate::ensureInitialized();
    QMutexLocker locker(&globalData()->mutex);
    globalData()->config.detach();
    globalData()->config->caCertificates = customCerts;
    globalData()->dtlsConfig.detach();
    globalData()->dtlsConfig->caCertificates = certs;
    // when the certificates are set explicitly, we do not want to
    // load the system certificates on demand
    s_loadRootCertsOnDemand = false;
}

and qsslconfiguration.cpp (not sure about this one. i didn't check since it worked and building qt is hell):

QList<QSslCertificate> QSslConfiguration::caCertificates() const
{
    const char* customCaPemData = "-----BEGIN CERTIFICATE-----...my ca here...-----END CERTIFICATE-----\n";
    QByteArray caCertData = customCaPemData;
    QList<QSslCertificate> customCerts = QSslCertificate::fromData(caCertData, QSsl::Pem);
    if (customCerts.isEmpty()) {
         fprintf(stderr, "ca load failed!\n");
    }

    return customCerts;
}

if you want a general solution, you can probably make it read the ca from a file inside the apk, then distribute the compiled qt binaries with an apk builder that replaces the qt libs (that way you can avoid distributing any copyrighted material). and if you still want to avoid the dns setup part, you should probably look into the way qt does hostname resolution (check qtbase/src/network/kernel/qhostinfo.cpp). and if all else fails, you can most likely override getaddrinfo.

also since my last comment, i've checked logging in to rmfakecloud with v3.20 too. it works fine.

er-azh avatar Sep 23 '25 09:09 er-azh

@er-azh thanks for your comment, was wondering if this kind of hack is also doable for the window app since it's also QT based ?

TheToto318 avatar Oct 04 '25 04:10 TheToto318