adolfintel / OpenPods

The Free and Open Source app for monitoring your AirPods on Android
https://fdossena.com/?p=openPods/index.frag
GNU General Public License v3.0
938 stars 161 forks source link

AirPods Pro? #34

Closed adolfintel closed 4 years ago

adolfintel commented 4 years ago

I need to know if the app works with the new AirPods Pro.

If it does, I also need some way to distinguish them from regular airpods to show the proper images.

yikeLiuAde commented 4 years ago

Hi man. I just bought an airpods pro. The app works fine. I really want to fight out how can I turn off the noise cancelling because I find no way to do it neither on my phone and on the airpods pro. On the airpods pro, I can only switch models between the noise cancelling model and the transparent model.

adolfintel commented 4 years ago

That's great. Now I need some way to distinguish them to show the proper images. Do you know how to use android studio?

yikeLiuAde commented 4 years ago

I have used android studio for 3 months. Wish I can help you. Just tell me how to do it.

adolfintel commented 4 years ago

Connect your phone and run the application from android studio, then connect your airpods. Let it run for a few minutes, then post the logcat output from the application.

yikeLiuAde commented 4 years ago

Yes sir~

yikeLiuAde commented 4 years ago

logd.txt

adolfintel commented 4 years ago

Thank you. This is the string that contains the airpods status, and possibly some way to identify the model: 0719010E200B998F0100050FDFE3570A22CA5478DEC0DF57A2973B

yikeLiuAde commented 4 years ago

Hi man. I don't have another airpods, but I will try to borrow the airpods 2 from my friends. I will let you know if I figure it out. By the way, do you have any idea about how to launch signals from android phones and let the airpods do something?

adolfintel commented 4 years ago

It's possible, but it requires more reverse engineering. Airpods have a proprietary protocol used to change settings like the name, gestures, etc.

dw881220 commented 4 years ago

reverse engineering is hard. thanks for the work. But still don't know other chars mean for noise cancelling or other settings.

f0s3 commented 4 years ago

The only way to find out is to compare data string when doing something, e.g. tapping, charging, etc. This way you will know what is changed.

adolfintel commented 4 years ago

Right now I'm more interested in finding something special in the string that lets us know that these are airpods pro and not 1st or 2nd gen, so I can show the proper images. Settings will require much more reverse engineering and analyzing communication between these things and an iPhone.

gji commented 4 years ago

It looks like the data string doesn't change when noise cancelling is toggled - it's possible that the status has to be queried somehow. The data string also doesn't change after the press and hold options are modified.

Incidentally, it does look like removing/inserting the airpods causes the last bit of the data string (after first 21 hex digits) to change, but it looks like it does so in a random way - everything seems to change in a non-deterministic way.

adolfintel commented 4 years ago

Keep in mind that OpenPods filters for a specific manufacturer specific data field, with a specific length of 27 bytes. The information you're looking for might be elsewhere, or have a different length. I suggest using some BLE scanner app to look at everything that the phone receives.

gji commented 4 years ago

Yeah, after some more digging it turns out the 10th nibble (mystery flip nibble) is actually the active microphone, which can be verified by manually changing it in settings on an iDevice. The nibble right after is related to if the active mic airpod is inserted (3), if the nonactive mic airpod is inserted (9), if both are inserted (B), or if both are removed (1). I think there are more status codes for if one is in a case, etc. To get automatic pausing when removing one airpod, I wonder if iDevices just have a higher rate of scanning or there's some other communication.

On the subject of detecting models, my airpod pros also have the same starting sequence of 0719010E20 as the other user reported, perhaps it's model-specific? I don't have any other ones to test on.

adolfintel commented 4 years ago

0719010E20 sounds promising. I'll compare it with my airpods 1st gen ASAP.

addcninblue commented 4 years ago

Hello! I'm interested in helping out, but I don't know much about reversing or Bluetooth much in general. I have a decent amount of experience in Linux and adb, though, so I tried to use an Android btsnoop_hci.log dump to see if I could find anything. Nothing in my log seems to be very useful, but I think that's also since I don't know what packets are important. How can I help out?

I can send the log files privately if that helps, but in the case that it contains personal information (it shouldn't), I don't want to post it publicly.

adolfintel commented 4 years ago

Sorry for the late reply. I need strings from several airpods pro, like the one that was posted before. The idea is to compare them to see which parts are in common, so we can correctly identify airpods pro and display the proper images.

You can sniff BLE traffic with a bluetooth adapter and wireshark, or just build OpenPods with Android Studio, this will give you a debug build that prints out those strings in the logcat window. I can help you with this if you don't know how to do it.

w00d3 commented 4 years ago

I analyzed the HCI Log,I think that when the noise reduction parameters of airpods are changed, SDP and L2CAP services are used

phire commented 4 years ago

I think nibble 7 might be the AirPods version. It's 0xE in both mine, gji's and yikeLiuAde's AirPod pros, and is 0x2 in the one other example string I found (I'm guessing 0x2 for airpod 2?)

I also agree with gji about the 11th nibble:

I couldn't find any bits which changed based on noise cancellation, but nibble 21 does appear to reflect playing status. 5 when playing, 4 when paused.

The last 16 bytes appear to be some kind of hash, every single byte changes when one of the preceding status bytes change, and the hash also appears to change periodically even when no status bytes change.

Here is a collection of hex strings (excluding the hash) from my AirPods Pros in various states:

0719010e202b668f010005
0719010e202b668f010005
0719010e202b668f010004
0719010e200b668f010005
0719010e2003668f010005
0719010e2001668f010005
0719010e2009668f010005
0719010e20536696530005
0719010e203366a6020005
0719010e202b768f020005
gji commented 4 years ago

The last 16 bytes appear to be some kind of hash, every single byte changes when one of the preceding status bytes change, and the hash also appears to change periodically even when no status bytes change.

My guess for the last section is that it's related to the auto-pairing mechanism that works with iOS devices - maybe some sort of pairing key.

adolfintel commented 4 years ago

@phire Your discovery will be very useful. I will implement the pro detection in the next 1-2 weeks and post a test build here.

Thanks to everyone for their help :)

phire commented 4 years ago

My guess for the last section is that it's related to the auto-pairing mechanism that works with iOS devices - maybe some sort of pairing key.

I actually think it's more important than that.

These status advertising reports come from a different mac address every time you take the airpods out of the case, and seem to cycle every 15min (to prevent long-term tracking of users)
Which means the iphone can't use the source mac address as a way of identifying which airpods status advertisement belong to your airpods.

I think the random hash is used to identify ownership of airpods.

My theory is the airpods hash the real mac address with a small counter (between 8 and 16 bits). The current advertising random address is probably hashed in too. This hash is appended to the advertising report.

Every time the airpods change state (or at periodic intervals) the counter increments, resulting in a new 256bit hash.

When the iphone sees a status advertising packet, it will hash the real mac address of any airpods it owns with every single value of the counter to see if one of these hashes match the hash in the packet.

If the hashes match, it knows the real mac address of the airpods that sent that message.

Unfortunately, this hashing algorithm probably isn't something we can guess. We might have to RE the code from the mac airpods driver to extract the correct algorithm. It also might not be possible to implement this algorithm on android, as the random advertising mac address (which I suspect is hashed in) isn't forwarded to apps using the SDK.

adolfintel commented 4 years ago

I finally had the time to implement the pro detection code. I've pushed the changes to master. Here's a test APK, let me know if it works for you: app-release.zip

Note that it's just a test so it won't look good, but it should work.

kevinheych commented 4 years ago

Tested and working on my s9.

When fully expanded in notification pulldown it displays the correct Pro image. When its compacted its showing the non-Pro images. Thanks for your work, willing to help

adolfintel commented 4 years ago

@kevinheych You're absolutely right, I totally forgot to update the smaller notification.

Here's an updated build: app-release.zip

I'll leave it here for a few days, meanwhile I'll work on finding some better images for the Pro model, then I'll release the new version.

netpro2k commented 4 years ago

This build works for me. Will try and capture some data packets for my pros as well to help with the RE efforts. We should start putting together a wiki page with all the parts of the payload we do understand, will be helpful for other projects wanting to decode this data (I want to make a utility i can pipe into i3-status to show battery levels on my linux laptop).

adolfintel commented 4 years ago

Yes I was thinking of making that wiki page as well, I can't find much about the airpods protocol online

haylanderlandim commented 4 years ago

First of all, congratulations on the job!

I've been debugging to find out the exact percentage of batteries, have you ever tried to increase the accuracy of this information?

adolfintel commented 4 years ago

@HaylanderLandim I don't know exactly how that second digit is stored. Looking at how my dad's iPhone behaves, I think it's completely fake, it gets the first digit from the airpods like this app does, then the second one simply decreases over time. I didn't reverse engineer the ROM though, so I might be wrong.

haylanderlandim commented 4 years ago

Understand. I'm going to do some tests with my girlfriend's iPhone.

Thank you so much for your attention!

netpro2k commented 4 years ago

Been digging around a bit capturing some logs. The last 16 bytes do seem like some sort of hash. They seem to change when any part of the rest of the payload changes. It also seems to change after some time interval even if no other data has changed (meaning some timer or counter also probably factors into this hash)

Also noticed some interesting behavior when removing a pod from the case. You start getting packets from 2 different MAC addresses at the same time (presumably the case and the removed pod). After the case shuts off it stops transmitting. Not itself super surprising, but it is interesting that the 2 seem to have different opinions about left/right earbuds (with what we think is the flip bit in the 10th nibble set on one and not the other, and the 11th nibble also different):

MAC1: 07 19 01 0e 20 15 a9 b6 01 00 04    bc83150d07486b4c57c619d6e9351d41
MAC2: 07 19 01 0e 20 71 9a 96 31 00 04    4cf49d7e968ece9be9c2a2eaca435740

Starting to also put together a quick lua disector for wiresshark for the info we already do understand to make further deciphering easier.

What's the best format to start documenting this? A C struct? Also we should probably move the discussion out of this issue hehe.

adolfintel commented 4 years ago

@netpro2k I'll make a wiki page for what we know and an issue where people can post their findings.

Personally I think the best way to document this would be informally: we explain how the airpods interact with the phone, where the data is in the BLE beacons sent by the airpods, and a list explaining what each nibble of that data is. Basically an extended version of the comment that I have in PodsService.java

adolfintel commented 4 years ago

New test build with improved pro handling and slightly updated looks. app-release.zip

steam3d commented 4 years ago

I tested on my iPhone. Only last bc83150d07486b4c57c619d6e9351d41 16 byte contains the battery lvl and maybe mac address. When i change something from it, my phone show wrong battery status. When i change other data like 0e 20 15 a9 b6 01 00 04 it nothing change on my iPhone. But iPhone will show message "it is not your airpods" if mac not the same.

akirataguchi115 commented 1 year ago

@adolfintel Could you link the Pull Request that implemented this feature or was this feature not implemented? If yes, then why?

akirataguchi115 commented 1 year ago

ping @adolfintel

adolfintel commented 1 year ago

@akirataguchi115 Support for AirPods Pro was added ages ago, I'm not sure what you're referring to

akirataguchi115 commented 1 year ago

@adolfintel Thanks for the clarification!😸