biemster / FindMy

Query Apple's Find My network
293 stars 47 forks source link

Use with device already in the network? #48

Open YeapGuy opened 8 months ago

YeapGuy commented 8 months ago

Hi, How technically feasible is it to modify this project to work with official AirTags or other Find My devices? Already working AirTag clones are being sold for $2-4 a piece on Aliexpress, so I don't see a point in spending a lot of time messing with flashing, firmwares and all of that stuff, when I can just buy a working "AirTag" for so cheap. The only issue for me is that I have an Android phone (I was able to set the tags up using a friend's iPhone), so I need to get something similar to this project working.

Systm21 commented 8 months ago

How technically feasible is it to modify this project to work with official AirTags or other Find My devices?

Its impossible, you need the private key and you won't get it from official devices.

Already working AirTag clones are being sold for $2-4 a piece on Aliexpress, so I don't see a point in spending a lot of time messing with flashing, firmwares and all of that stuff, when I can just buy a working "AirTag" for so cheap.

These Tags working with the official Findmy SDK, "our" Tags are working with reverse engineering, nothing official. The China ones are also only working with Apple Hardware, "our" Tags are not working official with ios (but with a workaround).

YeapGuy commented 8 months ago

I think I can retrieve the private key from the macOS application. Is that all I need?

biemster commented 8 months ago

The private key is all you need indeed, but that's stored in the Secure Enclave as far as I know. To my knowledge nobody knows how to get that, but if you have ideas please have a crack at it! (and report back here if you succeed)

YeapGuy commented 8 months ago

I successfully retrieved the keys from the macOS Find My application. Screenshot 2024-01-29 at 08 38 41 What's next?

biemster commented 8 months ago

the generate_keys.py script generates a random key here: https://github.com/biemster/FindMy/blob/8c2ce60f77f39ea8eca32a012ce319c13dc27b59/generate_keys.py#L28

If you change that line and put there the private key you found for your device, then the script generates a .keys file for it. Let me know if that works, and also how you retrieved the key please!

biemster commented 8 months ago

On top of that, in case you did find the correct key but you still get zero reports back, it's possible that your fake tag also implemented the key rolling as per spec so you should check if the advertised key from the tag is the same as the advertised key you generated.

biemster commented 7 months ago

@YeapGuy any luck on this? I just stumbled by accident on your swift gist https://gist.github.com/YeapGuy/f473de53c2a4e8978bc63217359ca1e4, did you by any chance use this?

YeapGuy commented 7 months ago

Yep, I used that to get the keys out of the macOS Find My app. See here for what I (or rather, Malmeloo) managed to do with this: https://github.com/malmeloo/FindMy.py/issues/4 Honestly, I'm quite lost in all of this Find My-related stuff, so I can't give a concise explanation. Best to read the linked issue for yourself, you'll probably understand better what's going on 😄

biemster commented 7 months ago

No you can't, trust me. The Code is rolling every 10 Minutes.

He can!

shiprec commented 7 months ago

@YeapGuy Is it possible to pull the reports of a device on the network that is not tied to your apple ID?

humpataa commented 7 months ago

I successfully retrieved the keys from the macOS Find My application.

Do you mind sharing how you did that?

biemster commented 6 months ago

Not abandoned :) actually the iOS17 issue (#40) seems to be just resolved, so I'm going to put a bit more time into this again.

Awesome that you managed to decrypt the .record files, I'm planning on adding a script for that here (although @malmeloo in https://github.com/malmeloo/FindMy.py seems to have picked up the ball and did wonderful things on this already)

Your comment is very hard to read, does the public key sent out by your tag in lost mode match the one in the request from request_reports.py?

samtombson commented 6 months ago

Hi @biemster, I hope you're well and haven't abandoned this project yet. I decrypted the .record file of an air tag that's already been added to icloud, got a decrypted.plist which contain:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
        <key>batteryLevel</key>
        <integer>1</integer>
        <key>cloudKitMetadata</key>
        <data>
        %MASKED%
        </data>
        <key>identifier</key>
        <string>%MASKED%</string>
        <key>isZeus</key>
        <false/>
        <key>model</key>
        <string></string>
        <key>pairingDate</key>
        <date>2024-03-24T11:28:16Z</date>
        <key>privateKey</key>
        <dict>
            <key>key</key>
            <dict>
                <key>data</key>
                <data>
                %MASKED%
                </data>
            </dict>
        </dict>
        <key>productId</key>
        <integer>21760</integer>
        <key>publicKey</key>
        <dict>
            <key>key</key>
            <dict>
                <key>data</key>
                <data>
                %MASKED%
                </data>
            </dict>
        </dict>
        <key>secondarySharedSecret</key>
        <dict>
            <key>key</key>
            <dict>
                <key>data</key>
                <data>
                %MASKED%
                </data>
            </dict>
        </dict>
        <key>sharedSecret</key>
        <dict>
            <key>key</key>
            <dict>
                <key>data</key>
                <data>
                %MASKED%
                </data>
            </dict>
        </dict>
        <key>stableIdentifier</key>
        <array>
            <string>%MASKED%</string>
        </array>
        <key>systemVersion</key>
        <string>2.0.61</string>
        <key>vendorId</key>
        <integer>76</integer>
    </dict>
    </plist>

I've bit changed generation in the generate_keys.py file like this

5a6
> from math import ceil
25c26
<     priv = random.getrandbits(224)
---
>     priv = int.from_bytes(base64.b64decode('%MASKED%'))
28,29c29,33
<     priv_bytes = int.to_bytes(priv, 28, 'big')
<     adv_bytes = int.to_bytes(adv, 28, 'big')
---
>     priv_length = ceil(priv.bit_length() / 8)
>     adv_length = ceil(adv.bit_length() / 8)
> 
>     priv_bytes = int.to_bytes(priv, priv_length, 'big')
>     adv_bytes = int.to_bytes(adv, adv_length, 'big')

generate a valid .keys file with a matching private key, but still can't get the location after executing request_reports.py. What am I doing wrong?

biemster commented 6 months ago

generate a valid .keys file with a matching private key, but still can't get the location after executing request_reports.py. What am I doing wrong?

did you confirm with something like nRF connect that your tag is broadcasting the same key as in the .keys file?

samtombson commented 6 months ago

Your comment is very hard to read

Sorry about that, was posting a comment from my phone and the layout broke, I fixed the post

does the public key sent out by your tag in lost mode match the one in the request from request_reports.py?

Unfortunately, no

biemster commented 6 months ago

It doesn't match or you didn't test? Sorry I did not read my own question well enough

samtombson commented 6 months ago

did you confirm with something like nRF connect that your tag is broadcasting the same key as in the .keys file?

In my case it's not possible, the tag is already far away from me and I can't just sniff signal

samtombson commented 6 months ago

It doesn't match or you didn't test?

The public key from the decrypted.plist does not match the public key I got from .keys file running _generatekeys.py, that's what I meant

biemster commented 6 months ago

It doesn't match or you didn't test?

The public key from the decrypted.plist does not match the public key I got from .keys file running _generatekeys.py, that's what I meant

Ok, are you able to craft a request with the public key from the decrypted plist? That should return reports. I think there is a bit of logic involved to generate derived public keys from the root private key you got from the .record. I did not work with that yet, but @malmeloo did so you'll probably find an answer if you ask in his repository.

samtombson commented 6 months ago

Ok, are you able to craft a request with the public key from the decrypted plist? That should return reports.

Yes. I'll give it try and let you know

malmeloo commented 6 months ago

You will not be able to directly retrieve reports using that key. The "shared secret" values in the plist you have are used as a seed which can be used to generate a sequence of keys for the AirTag; it then rotates through these keys on a timed interval to prevent other people from tracking you.

My library has a feature to find possible private keys for a given time period; you can check out an example here. You'll probably need to request location reports for all of the keys it generates in order to get an accurate location history.