Giter Site home page Giter Site logo

grindrplus's People

Contributors

eljaviluki avatar lanchon avatar r0rt1z2 avatar robbietechie avatar tebbeubben avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

grindrplus's Issues

Grindr forcing to update its client app

Before knowing this mod, every time a new version of Grindr came out the app would stop working until I updated it, like a connection error, it happened to me with version 8.12 when version 8.12.1 came out, and it happened again when it came out version 8.13. when I found this mod and had to go back to version 8.11 to use it I didn't have a problem again, but now that the mod was updated to version 8.17 the same problem is happening to me, I can't use Grindr without updating to version 8.17.1 , I get a connection error. for now I went back to version 8.16 which works for me, but I would like to know if this problem occurs to someone else or is it a problem with my device.

sorry for my bad english, i only speak spanish, google translate is to blame 🀣

About the BMI Profile Field and other additional fields

version: v1.1 (for v8.17.1)

in the recent builds, added profile fields were re-enabled.
this triggers a nasty bug involving the BMI field when i view my own profile.

expected result: my profile says normal weight
actual result: damn thing says i'm overweight!
workaround: avoid looking at my own profile
lol im kidding :-p

Unable to login

Currently using Latest version of LsPosed (Zygisk) with this and I'm getting errors that say to check my connection or something went wrong.

I have no VPN or Custom DNS enabled. This doesn't seem to be due to the hook but i can't find the cause of it

Extra Details:
Device: OnePlus 8 5G UW (IN2020)
Android Version: 11
ROM: OxygenOS
Magisk: Hidden
SafetyNet: Passing
Grindr Version: 8.23.0

Unlocked filters not working anymore

You "unlocked" the functions, but they don't work, they are only activated for the application.
At least those that have to do with remote chats do work.

[Garbage]

I'm sure most of you know how to get Grindr back up and running from the Pull request but I feel me and some others are sadly left behind as we honestly don't have a clue what to do. Is anyone kind enough to help out on how to get it working? I'm currently on 9.6.0

I would highly appreciate this and others too!

Sugestion: Bypass Device Ban

It's been a while since I was banned from grindr, and to this day I still do not know the reason, since they say I broke a rule, which? do not quote.

And I wanted to circumvent the ban, I tried some xposed modules to circumvent the deviceid and everything else, but to no avail.

I imagine that they use the IMEI to ban the device, then it would be good if there was a function to circumvent this through the module itself

Grindr forcing to update its client app to 9.6.0

Forced to update to V8.17.1, I tried to modify the version in the file app\src\main\java\com\eljaviluki\grindrplus\Hooker.kt, make an .apk with android studio but it's not OK… I'm not a programmer so I don't know what to do....

Not loading an unlimited profile

Almost everything works as one would expect, but when clicking on a profile in the Unlimited section, it loads the very first profile in the grid instead. Everything in the xtra section will load a profile properly, after that only the very first profile loads, meaning that clicking a profile in an Unlimited section loads the very first profile of the entire grid. Watching the API, it doesn't appear there is even an attempt to fetch the profile data if you are past the xtra section and inside the unlimited area.

A Discord server?

Hi guys, I wonder if you would like to join a new Discord that I would create to share our experience on the app and make this project more engaging and cooperative.

I should assign the task of moderation and maintenance of that hypothetical server to several people, since it is something that I cannot spend my time alone with, much less under personal circumstances.

I look forward to ideas on how to organize everything. Honestly, I don't have much knowledge in setting up servers on Discord today, but this could be a great opportunity for that to stop being true.

Cheers!

About the project maintenance

Will the app continue to be updated or has the project been abandoned? I see that Grindr is already several versions ahead and the project has been two months without news

increased user accountability

hi, thanks, great work!

a shitty thing about grindr is that the service tries to convey a fake sensation of unlimited guys. it does this by deleting old messages, unblocking profiles you previously blocked, and the like. a user can also block you and immediately unblock you to wipe your message history, in which the user might have acted impolitely and you might have chosen to thumb him down for it for instance.

i once hacked grindr and did several changes to lessen the impact of the "no history" features of grindr. some changes i remember:

  • when a chat object was received, if it was a remote block, i changed its type to a text chat message containing the string "[block]". that way the history would remain -pics and all- and i would be notified of the blocking. remote wiping would fail, and i could also block them on other platforms so i wouldn't waste time on that guy again.
  • when i blocked a profile, an outgoing "[block]" text would be added to the local message table. then the thread would be removed from the message thread table, but the associated messages would not be purged. so the next time grind unblocked us, i would find the history there anyway (including my block). but i could still remove the thread from view by blocking.
  • i also disabled the deletion of old messages, and there was something done to the local profile cache to support that. (watch it! the db would grow and the app would get very slow. and i had to add missing indexes to the local sqlite db (the app was THAT bad, lol).)
  • whenever the app received a profile, it updated the local profile cache. i made it so that info would be updated but not deleted from the local cache. so if somebody hid or removed data, i would see the old data instead.
  • and in particular, when somebody changed their profile pic (there was only one pic per profile then) my app would fake a received message: the old pic would be stored in the chat as a received message. so whenever i opened a chat, i could see all their past profile pics. it was GREAT to spot fakes.
  • this was kinda creepy but fun: it also logged all other changes to the profiles as received messages: changes in name, description, age, height, weight, etc. some people were really weird in how the utterly lied about everything.
  • finally all "synthetic" chat messages were permanently marked as "now being delivered" (even the received ones -it worked) so that they would be a different color for easy visual identification (they would be shaded down). also most synthetic chats would not generate receive notifications (but blocks would).

many other changes, but those were most of the ones related to increased accountability. anyway, just food for thought.

Hidden Features

I don't know where to ask but here. I just want to learn more about the "hidden features" that this mod enabled per the "Extra Features" on the ReadMe. I want to know what these features are, because obviously, they're hidden. I hope Javi can elaborate on this more. I love this mod to bits.

Filters not working

You can choose filters but they aren't working correctly. At least the online now doesn't

Errors in Logcat for the added profile views

I'm getting errors for the added profile views, even though they are showing up and working, there are errors there in logcat. I downloaded and compiled the code and commented out that section and the errors are gone. This started happening a few versions of Grindr ago.

My concern is the errors being sent to Grindr as I had one of their employees message me in the past on XDA letting me know that an old patch that had errors for people jwas being sent to them, I think through crashlytics.

I've tested this one a couple devices, one with EdXposed and another with LSPosed, both get the errors about the params being null even though the profileID shows up and the mod works fine. EdXposed was on Android 9 but I wasn't sure if that is the issue there. Below are parts of the log copied from logcat, with date and time removed...

Thank you for the awesome mod and all the hard work you've put into it!! It's appreciated.

[date/time redacted E/LSPosed-Bridge]
java.lang.NullPointerException: param.args[0] must not be null
at com.eljaviluki.grindrplus.Hooks$addExtraProfileFields$1.afterHookedMethod(Hooks.kt:121)
at de.robv.android.xposed.XposedBridge$AdditionalHookInfo.callback(Unknown Source:147)
at LSPHooker_.h(Unknown Source:14)
at com.grindrapp.android.ui.profileV2.ProfileFieldsView$a.invokeSuspend(Unknown Source:12)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(SourceFile:4)
at kotlinx.coroutines.DispatchedTask.run(SourceFile:18)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:241)
at android.app.ActivityThread.main(ActivityThread.java:7617)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)

[date/time redacted E/LSPosed-Bridge]
java.lang.NullPointerException: param.args[0] must not be null
at com.eljaviluki.grindrplus.Hooks$addExtraProfileFields$1.afterHookedMethod(Hooks.kt:121)
at de.robv.android.xposed.XposedBridge$AdditionalHookInfo.callback(Unknown Source:147)
at LSPHooker_.h(Unknown Source:14)
at com.grindrapp.android.ui.profileV2.ProfileFieldsView$a.invokeSuspend(Unknown Source:12)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(SourceFile:4)
at kotlinx.coroutines.DispatchedTask.run(SourceFile:18)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:241)
at android.app.ActivityThread.main(ActivityThread.java:7617)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)

No typing/read status if both parties have mod

I tested with a friend, once we both have the mod enabled, we were not able to see typing status or read status on messages sent between us, it works for other who don't have the mod.

Unlimited albums

Grindr Xtra and unlimited allows you to create up to 10 albums, is it possible to add this function to the mod? It would be more comfortable to send an album according to the role of the other person, so I don't show everything πŸ€­πŸ˜‚πŸ˜‚

ReVanced-style binary patching?

Hi,

I can't root, but I'm interested in the module. Would it be possible to distribute this mod as a binary patch for a known version of Grindr (for ReVanced, for example)?

Analytics still being recorded

The new release is still sending analytics logs to /v3/logging/mobile/logs

The api reference was updated from
const val AnalyticsRestService = "$_api.c"
to
const val AnalyticsRestService = "$_api.b"

Also the option to send videos in chat does not show up, just the live chat option. If I disable the mod or just the Session Implementation and Feature Granting and rebuild the mod then the sending videos in chat option shows up again

Problem with saving conversations

Hi ! It is impossible to connect to my Google account from the application with the mod (mod installed from Lspatch with Shizuku), is there a solution for this? It says that it's not possible to connect to Google because the app is currently being tested, and that you have to be a grindr developer... Thank you!

Grindr prevention app from working at all if rooted

NOT TOTALLY RELATED TO THIS MODULE ,but on old phones (rooted with inbuilt lineage OS tool not Magisk ) grindr after version 8.12 added lots of code in smali (class 3) to check for root and preventing the app from working at all regardless of xposed .
so please if possible add someway to hide root with your mods otherwise grindr will never even connect to the server ,thanks

Usage of multiple accounts

Hello,

Does Grindr have a HWID system in place?

As far as I know, usage of multiple accounts and/or sharing accounts is prohibited and can lead to permanent deactivation of all accounts, and I assume they use IDs from your Android device to assure you are respecting their accounts policy.

With that being said, I would like to know if you have information on which identifiers are used, and if it'd be possible to create a hook to disable these verifications or to spoof them.

I'd love to help creating a hook for it, but for that I would need some info on where to get information from the Grindr .apk, as I don't know much about Xposed hacking, etc.

A Discord server would be fantastic for discussing such things!

Hack no longer works

Greetings! It seems like versiΓ³n 9.9.1 is patched. Can you plz update the app so we can all enjoy this amazing module πŸ‘

Can literally anyone update this to 9.8.0?

I get that the guy doesn't want to code anymore or whatever but i'm not paying whatever obscene amount they're charging for me to filter who I've talked to, I just want my macro to work properly so I don't message the same people 5 times a day.
Can anyone fix this thing or at least point me to another way to get something like a bypass or something?

Frida version of the hooks

Hi,

Relying on XPosed framework might not be the easiest way to hook / debug (although this might be my own lack of familiarity with this framework).

I've written two (very dirty) scripts to convert the hooks to a Frida JavaScript script. Ideally, relying on frida gadget this might remove as well the need for rooting.

Everything is automatically converted except for the addExtraProfileFields hook which is having a bit too much logic for a straightforward JS generation.

Happy to take feedbacks on this, and if Frida compatibility is something useful for others, I think it should be possible to refactor the current code to ease automatic generation to both XPosed and Frida.

Here are the useful scripts. They are very dirty at the moment and only meant as a PoC.

My main script is :

# Add our mock of Constants
cat > grindrplusfrida.js <<EOF
var Constants = {
    GRINDR_PKG: "com.grindrapp.android",
}
EOF

# Fetch latest Obfuscations from upstream and convert to Frida-readable script
curl "https://raw.githubusercontent.com/ElJaviLuki/GrindrPlus/master/app/src/main/java/com/eljaviluki/grindrplus/Obfuscation.kt" | sed -e "s/^package.*//" | sed -e "s/object \(.*\) {/\1: {/" | sed -e "s/const val \(.*\) =/\1:/" | sed -e "s/private//" | sed -e "s/^Constants:/var Constants =/" | sed -e "s/^Obfuscation:/var Obfuscation =/" | sed -e "s/\"$/\",/" | sed -e "s/ }/ },/" | sed -e "s/\([a-zA-Z]\)$/\1,/" >> grindrplusfrida.js

# Add our custom mocking
cat >> grindrplusfrida.js <<EOF
// Mock GApp / Hooker / Build
const GApp = Obfuscation.GApp;
const Hooker = {
    pkgParam: {
        classLoader: undefined,
    }
};
const Build = {
    VERSION: {
        SDK_INT: Java.use('android.os.Build\$VERSION').SDK_INT
    }
}

/**
 * Handle templating in GApp variable.
 */
function applyReplacements(obj, parent) {
    if (typeof obj != 'object') {
        return obj.replace(
            /\\\$(_[a-zA-Z]*)\./,
            function replacer(match, p1) {
                return parent[p1] + '.';
            }
        )
    }
    for (let key of Object.keys(obj)) {
        obj[key] = applyReplacements(obj[key], Object.assign({}, parent, obj));
    }
    return obj;
}

// Useful return values
const RETURN_TRUE = function () { return true; }
const RETURN_FALSE = function () { return false; }
const RETURN_LONG_MAX_VALUE = function () { return Java.use('java.lang.Long').MAX_VALUE };
const RETURN_INTEGER_MAX_VALUE = function () { return Java.use('java.lang.Integer').MAX_VALUE };

/**
 * Fake Duration class
 */
class Duration {
    constructor(duration) {
        this.duration = duration;
    }

    inWholeMilliseconds() {
        return this.duration;
    }
}

/**
 * Mock listOf
 */
function listOf(...args) {
    return args;
}

/**
 * Frida implementation of findClass
 */
function findClass(className) {
    const classLoaders = Java.enumerateClassLoadersSync();

    for (const classLoader in classLoaders) {
        try {
            classLoaders[classLoader].findClass(className);
            var classFactory = Java.ClassFactory.get(classLoaders[classLoader]);
            return classFactory.use(className);
        } catch (exc) {
            continue;
        }
    }
}

/**
 * Frida implementation of getStaticObjectField
 */
function getStaticObjectField(loadedClass, fieldName) {
    return loadedClass[fieldName];
}

/**
 * Frida implementation of setStaticLongField
 */
function setStaticLongField(loadedClass, fieldName, value) {
    loadedClass[fieldName] = value;
}

/**
 * Frida implementation of findAndHookMethod
 */
function findAndHookMethod(loadedClass, methodName, ...args) {
    if (args.length == 1) {
        // No extra arguments, last one is implementation
        loadedClass[methodName].overloads[0].implementation = args[0];
    } else {
        // Multiple arguments, last one is implementation
        const implementation = args.pop();
        // Find correct overload based on types
        const overloadSelectionTypes = args.map(
            function (type) {
                if (typeof type == 'string') {
                    return type;
                } else {
                    return type.\$className;
                }
            });
        // Rewrite implementation
        if (typeof implementation == 'function') {
            loadedClass[methodName].overload(...overloadSelectionTypes).implementation = implementation;
        } else if (typeof implementation == 'object') {
            loadedClass[methodName].overload(...overloadSelectionTypes).implementation = function (...functionArgs) {
                const param = {
                    thisObject: this,
                };
                if (implementation.beforeHookedMethod) {
                    // TODO
                }
                this[methodName](...functionArgs);
                if (implementation.afterHookedMethod) {
                    implementation.afterHookedMethod(this);
                }
            };
        }
    }
}
EOF

# Fetch latest implementations of hooks from upstream and convert to Frida-readable version
curl "https://raw.githubusercontent.com/ElJaviLuki/GrindrPlus/master/app/src/main/java/com/eljaviluki/grindrplus/Hooks.kt" | sed -e "s/^    }/    },/" | sed -e "s/^package.*//" | sed -e "s/^import .*//" | sed -e "s/fun /function /" | sed -e "s/val /var /" | sed -e "s/String::class.java/'java.lang.String'/" | sed -e "s/Boolean::class.javaPrimitiveType/'boolean'/" | sed -e "s/override fun/fun/" | sed -e "s/function afterHookedMethod/afterHookedMethod: function /" | sed -e "s/object Hooks /var Hooks = /" | sed -e "s/    function \([a-zA-Z]*\)(/\1: function \(/" | sed -e "s/function\(.*\)(\(.*\):.*)/function\1\(\2\)/" | python generate.py >> grindrplusfrida.js

# Append our custom execution code
cat >> grindrplusfrida.js <<EOF
// Reimplementation from https://www.securify.nl/blog/android-frida-hooking-disabling-flagsecure/
Hooks.allowScreenshotsHook = function() {
   // https://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_SECURE
   var FLAG_SECURE = 0x2000;
   var Window = Java.use("android.view.Window");
   var setFlags = Window.setFlags; //.overload("int", "int")

   setFlags.implementation = function (flags, mask) {
      flags &= ~FLAG_SECURE;
      setFlags.call(this, flags, mask);
      // Since setFlags returns void, we don't need to return anything
  };
}


Java.perform(function () {
    applyReplacements(Obfuscation, {});

    Hooks.allowScreenshotsHook();
    Hooks.hookUserSessionImpl();
    Hooks.unlimitedExpiringPhotos();
    Hooks.hookFeatureGranting();
    Hooks.allowSomeExperiments();
    Hooks.allowVideocallsOnEmptyChats();
    Hooks.allowMockProvider();
    const threeMinutes = new Duration(3 * 60 * 1000);
    Hooks.hookOnlineIndicatorDuration(threeMinutes);
    Hooks.unlimitedTaps();
    Hooks.removeExpirationOnExpiringPhotos();
});
EOF

And it requires an extra generate.py script:

import re
import sys


def removeFunctionBlock(script, startMatch):
    start = script.find(startMatch)
    start_idx = start + script[start:].find('{') + 1
    counter = 1
    for idx, char in enumerate(script[start_idx:]):
        if char == '{':
            counter +=1
        elif char == '}':
            counter -=1
        if counter == 0:
            break
    return (script[:start_idx] + '}' + script[start_idx + idx + 1:])


def forEachSyntax(script):
    forEach_idx = [
        m.start() for m in re.finditer('forEach', script)
    ]
    for start_idx in forEach_idx:
        first_brace_idx = script[start_idx:].find('{')
        counter = 1

        for idx, char in enumerate(script[start_idx + first_brace_idx + 1:]):
            if char == '{':
                counter +=1
            elif char == '}':
                counter -=1
            if counter == 0:
                break
        block = list(
            script[start_idx + first_brace_idx: start_idx + first_brace_idx + idx].strip()
        )
        block[0] = '('
        block = ''.join(block)
        block = block.replace('->', '=> {') + '})'

        script = (
            script[:start_idx + first_brace_idx]
            + block
            + script[start_idx + first_brace_idx + idx + 2:]
        )
    return script


def XC_MethodHook(script):
    XC_idx = [
        m.start() for m in re.finditer('object : XC_MethodHook\(\){', script)
    ]
    for start_idx in XC_idx:
        first_brace_idx = script[start_idx:].find('{')
        counter = 1

        for idx, char in enumerate(script[start_idx + first_brace_idx + 1:]):
            if char == '{':
                counter += 1
            elif char == '}':
                counter -= 1
            if counter == 0:
                break

        block = script[start_idx : start_idx + first_brace_idx + idx]
        block = block.replace('XC_MethodHook()', '{ XC_MethodHook: ')
        script = (
            script[:start_idx - 1]
            + '{' + block + '}}'
            + script[start_idx + first_brace_idx + idx:]
        )
    return script


if __name__ == '__main__':
    script = sys.stdin.read()

    script = removeFunctionBlock(script, 'allowScreenshotsHook: function')
    script = removeFunctionBlock(script, 'addExtraProfileFields: function')

    script = forEachSyntax(script)

    script = XC_MethodHook(script)

    print(script)

Best

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.