JustArchiNET / ArchiSteamFarm

C# application with primary purpose of farming Steam cards from multiple accounts simultaneously.
Apache License 2.0
11.15k stars 1.05k forks source link

【Wiki Enhancement】New ways to export steam-guard on Steam3.0 for Root Android Device #2746

Closed MuelNova closed 1 year ago

MuelNova commented 1 year ago

Checklist

Enhancement purpose

Though steam app has upgraded to 3.0 for a while, new method for exporting steamguard was not there except to downgrade the application to 2.X.

In that case, I took some time to reverse the application and discovered few solutions, which would be easier to export steam guard without modifing the app.

In order to do that, we need frida to hook the Cipher.doFinal function.

Solution

import json
import frida
import sys

package = "com.valvesoftware.android.steam.community"
cmd = """
'use strict;'

if (Java.available) {
  Java.perform(function() {

    //Cipher stuff
    const Cipher = Java.use('javax.crypto.Cipher');

    Cipher.doFinal.overload('[B').implementation = function (input) {
        var result = this.doFinal.overload('[B').call(this, input);
        send(result);
    }

  }
)}
"""

def parse_hook(cmd_):
    print('[*] Parsing hook...')
    script = session.create_script(cmd_)
    script.on('message', on_message)
    script.load()

def on_message(message, _):
    try:
        if message:
            if message['type'] == 'send':
                result = "".join(chr(i) for i in message['payload'])
                print(json.dumps(json.loads(result), indent=2, ensure_ascii=False))
    except Exception as e:
        print(e)

if __name__ == '__main__':
    try:
        print('[*] Spawning ' + package)
        pid = frida.get_usb_device().spawn(package)
        session = frida.get_usb_device().attach(pid)
        parse_hook(cmd)
        frida.get_usb_device().resume(pid)
        print('')
        sys.stdin.read()

    except KeyboardInterrupt:
        sys.exit(0)
    except Exception as e:
        print(e)

if everything goes well, your steam app would be automatically opened and all your steam guards would be shown in the stdin.

Why currently available solutions are not sufficient?

For most people who don't have CorePatch (or some similar app) installed, a downgrade installation is not allowed unless the original application is uninstalled. Thus, they have to remove (if not exported before) their old steam guards in order to add new steam guard, which would take them another 15 days to wait.

With frida hook method, the initial set up might be a bit annoying. But once everything is set up, every time you add a new steam guard, all you need to do is start the "frida android server" and run the script again. You don't have to forcibly backup all your accounts' steam guard and to recover them everytime when you want to add a new steam guard.

I can't really say this is a generally-available method, but so far, this is the best and easiest way I can found.

Can you help us with this enhancement idea?

Yes, I can code the solution myself and send a pull request

Additional info

This is not the only method I discovered, see blog(Chinese) for other methods like React Native Javascript Injecting or Packet Capturing Method and detailed analyzation for new steam-guard file SecureStore.xml

JustArchi commented 1 year ago

It looks good enough to include it on the wiki, but before doing so I need to verify myself that this method works flawlessly, and preferably have somebody else doing the same. Thanks for bringing it up to our attention, I'll leave the issue open until I have the time and willings to give it a try.

@Abrynos @Ryzhehvost feel free to verify in the meanwhile.

Abrynos commented 1 year ago

Sorry. I don't even have the original Steam app installed. I can't test this.

NellClarke commented 1 year ago

@Nova-Noir

android 13 root by magisk 25.2 frida 16.0.5 steam app 3.0 from google play

frida is set, connect the phone with USB ADB. run frida-ps -U will show every app on the phone, ensuring the basics are working.

use python to run your py script, the steam app will open, but nothing shows.

MuelNova commented 1 year ago

I'm currently using Android 12, I'm not sure if anything about Keystone was changed in Android 13.

Is it possible to hook another function to see if frida is working well?

I disassembled Steam App and confirmed that the decrypt method uses Cipher.doFinal(Byte[]), so it should work if this function is hooked correctly.

There's a problem that I never used Frida so I know few of frida script, so maybe the script is not working well? Maybe you can try to write a new script just remember to hook the Cipher.doFinal(Byte[]) method.

Or, if something was changed in Android 13 that doFinal is no longer allowed to be hooked, you can try hook the Cipher Object and then use it to decrpyt.

NellClarke commented 1 year ago

@Nova-Noir

I searched for some frida scripts and replace cmd in your py script, like this one.

https://github.com/berkayyildi/Frida-Android-Hooking/blob/master/AES_HOOK.txt

After steam app auto open, I enter to 2fa page and switch to show steam guard code.

I can get some output, but it seems to report an error.

'str' object cannot be interpreted as an integer

Since I'm not familiar with encryption and programming, I don't know how to modify it to make it work, but this maybe proves that frida can hook on android 13.

MuelNova commented 1 year ago

Thanks for your comments. I'll investigate it and test it on my android 13 emulator (this may takes few days 'cause I'm moving house)

For the error you mentioned, it is because I modified the output to make it prettier.

You can try replace the function on_message with the code below

def on_message(message, _):
    try:
        if message:
            print(message)
    except Exception as e:
        print(e)

Doing this, run the script again, you should be able to see some outputs with replaced cmd.

wuhgit commented 1 year ago

@iknownothingaboutgit @Nova-Noir

Android 13 and Magisk 25.2, have the same problem also. but then solved it.

You need to force stop the Steam app and clean the cache data, note clean the cache only, not storage, DON'T DO IT WRONG, otherwise you will lose the existing TOTP data.

The python script will output errors sometimes, and the Steam app may not show any guard code and show move authenticator from other devices, don't do it at this time, My guess that is some kind of security protection probably because you injected unrelated code.

2022-12-02_16-10

End the python script, kill the Steam app, clear the cache, and run the python script again, until successful.

I probably tried five or six times before I succeeded.

2022-12-02_16-07

I have two steam accounts, stored the data I got with python script in separate maFile with bot name, imported them in ASF-UI, and now everything works fine!

Big thanks to @Nova-Noir 🎉

MuelNova commented 1 year ago

Oh yes! This could be the issue as my steam was always re-installed for test.

Maybe steam will decrypt the data only when it can't find the decrypted data stored, thus, we might be able to find a more efficient way to get the decrypted data.

For the problem you mentioned that steam asks to move the authenticator from other devices, it is because that the script blocks Steam's original function, and then it will call the original function after we get the data. Thus, if any error occured, the script will still block the function but no calls to the original function. Because no value returns, Steam then think that there's no any guard on this device.

Thanks for your test and solution!@wuhgit

NellClarke commented 1 year ago

@Nova-Noir @wuhgit

I made it! you guys rock!

Uklosk commented 1 year ago

Hi, I get a timeout when running frida-ps -U to check the frida-server connection.

The server seems to be running without errors.

MuelNova commented 1 year ago

I'm not sure what had happened, could you provide more info / log?

MuelNova commented 1 year ago

@wuhgit But I still have a question there. From what I have discovered, the script hooks the Cipher.doFinal method, and it will be called whenever the app launches ( As I mentioned in my blog, I changed index.android.bundle using React to print the json. However, it will call the function using Cipher.doFinal and later store the decrypted data in memory, which uses to show the TOTP codes ) If so, there isn't anything about steam guard that cache will store. But from your comments, there seems to be something with cache? IDK what exactly has happened now :(

wuhgit commented 1 year ago

@Nova-Noir

I can confirm that I must clear the cache to make the script work. otherwise, the script will not have any output.

I created a new authenticator a few days ago because I need totp-secret for password manager, this seems to be only available by capturing network packets when first requested.

After I got the totp-secret, I use your script for ASF again. as I said, kill the Steam app first, then clear the cache, run your script, I got everything I need.

xPaw commented 1 year ago

I've suggested it before, but this method of setting up authenticator on multiple "devices" gives you the same secrets, so this method should still work using steamctl without root: https://github.com/ValvePython/steamctl#previews

JustArchi commented 1 year ago

ASF could in theory do the same.

For somebody who doesn't have 2FA set up yet:

This is insane security hole. I don't know how I should feel about making it possible sigh.

MuelNova commented 1 year ago

Well, in Steam version 3.0.0, it will automatically migrate the old guard file. The state will be stored in a file /data/data/com.valvesoftware.android.steam.community/databases/RkStorage.db. If you have old guard files or have the ability to create a new guard file using ASF or steamctl, you'll be able to migrate them by changing the value of bMigrated in the database file or simply deleting it.

Just as said, creating secret using third parties may be vulnerable, and steam may remove that API in the future due to the breaking changes of Steam3.0 and consideration of security.

But this is definitely a workable method for most people who doesn't have a root phone or is not able to set up Frida or change the apk. Instead of exporting a existing guard file, create a new guard file would be much easier, and there is actually a tool calls watt toolkit can do that.

Thanks for your comment!

wuhgit commented 1 year ago

@Nova-Noir

I seem to have found the reason. Clearing the cache and kill the app may be unnecessary. I just tested it in airplane mode and I was able to get the results immediately every time.

P.S. Because I need to use VPN to connect to Steam, not sure if this is the cause of the problem.

Bluscream commented 1 year ago

Is this the same issue that causes The sign in request has expired on every login?

JustArchi commented 1 year ago

@Nova-Noir sorry for delay, I was really busy this last month-two dealing with MatchActively and other stuff, but I didn't forget about this issue.

I presume that https://novanoir.moe is your website, judging by your username. Would you be so kind to offer the original article under https://novanoir.moe/en/blog/2022/11/20/%E3%80%90ROOT%20Android%E3%80%91Steam%203.0%20%E5%AF%BC%E5%87%BA%E4%BB%A4%E7%89%8C%E7%9A%84%E6%95%B0%E7%A7%8D%E6%96%B9%E6%B3%95/ in English perhaps? I think you deserve the credit for finding out about this method and documenting it like you did, and I'd be happy to link to your website for updated steps (if any) and further explanation.

I plan to get down to verifying this method in following days, if it works as described I plan to write a very simplified guide on how to get it working and then link to your website for additional details and original credit, hence why I believe it'd be of great help if the article was also available in English :slightly_smiling_face:

MuelNova commented 1 year ago

Sure, but it may takes days as I'm still preparing for my final exams. I will update the English version and also add some details then.

JustArchi commented 1 year ago

Don't worry, I know a thing or two about that :sweat_smile:, no need to hurry, good luck in your exams! :+1:

JustArchi commented 1 year ago

Gave it a try but it doesn't work for me. In particular frida-server looks like permanently frozen after start, tried both arm and arm64 version, no go.

obraz

Therefore the script gives:

[*] Spawning com.valvesoftware.android.steam.community
timeout was reached

Doesn't seem like viable option considering it didn't work on my rooted LineageOS, let alone other ROMs and devices. Tried with 16.0.8 and 15.2.2, no luck.

JustArchi commented 1 year ago

Made it work using 15.2.2, Steam app opens but nothing further happens:

[*] Spawning com.valvesoftware.android.steam.community
[*] Parsing hook...

Maybe the script doesn't work with latest Steam beta version. I did try your suggestion of forcing Steam app to stop and cleaning its cache, didn't work.

It's definitely not robust enough to consider for now, maybe it'd make more sense to find out how to efficiently decrypt what Steam has stored in its encrypted file instead - since we're on rooted device, an option is to impersonate official Steam community app and force the OS to hand out descryption keys that would allow us to read SecureStorage.xml. I'm not an Android expert and neither I have the time to dig into this now, but if official Steam app is able to do anything, then by definition root user that controls whole OS is able to do the same, the only question remains how difficult that is.

I'm converting this issue into a discussion, since there is nothing to do for now in regards to wiki improvements.