A few months ago, I started looking into using a Raspberry Pi (I’m gonna call it rPI from now on) as an access point / media server for the car. It started off as a way to let my boys play Minecraft with each other during long car trips….and then kind of went a little over the top after that.
In June, an interesting AppleTV hack called PlexConnect got some press, and I started thinking about trying to get videos from the rPI onto an AppleTV.
While I’ve had AppleTVs for years (since shortly after the first, non-iOS units were introduced), I hadn’t really looked into how they worked until recently. One question I had was: How do developers test the applications they write for the AppleTV? Because there had to be developers…I didn’t really think Apple was writing the 3rd party channel apps…
About this time, Apple updated the channels available on AppleTV. One of the new channels added was SkyNews, and so I spent a little time looking through their videos. I happened upon a short segment discussing the AppleTV (how meta), and saw something interesting. At one point, the camera panned across a flat screen TV on a table in their studio. It was showing the AppleTV home screen, with the “normal” apps, plus the SkyNews app, plus the WWDC app. But none of the other apps which had just been introduced. So it seemed likely that this was filmed sometime in June (because that’s the only time the WWDC app was there) but before the other apps were installed. Which meant that this was some kind of developer unit.
And in the corner of the screen was a blank application tile labeled “Add Site.”
I spent a week digging through configuration files, property lists, application binaries, and tearing things apart in IDA pro. The result of all this was a method that can be used to easily put additional applications onto a stock, non-jailbroken, AppleTV. (I used a jailbroken AppleTV for most of my research, but this works on non-jailbroken devices as well).
But before I get into that, a quick note about how AppleTV applications work. They’re not really applications, per se. An application (or channel or feed or whatever you want to call it) isn’t a binary, compiled for the AppleTV and loaded onto the device. Instead, it’s a all web-based, using a mix of XML and Javascipt files, which are then interpreted in a single AppleTV.app and converted into what you see on the screen.
This is one reason all the AppleTV channels have such a consistent look and feel — they’re all just calling stock library functions to build out menus, preview screens, etc.
While trying to write my first AppleTV app, I quickly decided that my workflow (write python to generate XML, turn around, pick up the AppleTV remote, see how it looks, turn back to the computer, etc.) was just too slow. So I wrote an AppleTV “simulator.” It’s just a simple Python script that acts as a web proxy. It fetches an AppleTV application page from a remote server, applies an XSL transform and appends a CSS file, then returns the result to the browser. Ideally, the result is a web page that looks a lot like the equivalent page in an AppleTV.
But I’m getting ahead of myself. Looking through the AppleTV binary, I found all kinds of interesting strings. Configuration settings to enable diagnostics, set the device name, and the intriguingly-named “EnableAddSite”. I generated a simple profile using Configurator.app (or maybe I found a template online somewhere — I don’t really remember) and tried to figure out how to test out all these settings.
The official way to load a profile on an AppleTV is slow and cumbersome, requiring disconnecting the device from the TV, connecting it to a computer using a USB cable, pushing a profile onto the device, then reconnecting it to the TV. This isn’t really feasible for high-volume fuzzing of a dozen or more configuration settings.
So I tried using Mobile Device Management, which also didn’t work — I could install the MDM profile, but couldn’t make the device enroll in MDM. Because I was working on a jailbroken unit, I was able to force polls of the MDM server, and so tweaked the server to send different profiles with each request. This simple approach let me test out all kind of values for settings — with the theory that bad values would generate errors, and good values would be set aside so I could manually investigate what they did. Turns out, this didn’t work either, because the AppleTV didn’t really care if I set a ludicrous value for something.
And nothing I did would make the EnableAddSite key work.
In the end, I used IDA Pro to disassemble and decompile the AppleTV binary, and eventually found a boolean function “AddSiteIsEnabled” that checks to see whether the right profile had been loaded.
Basically, the function:
- Loads up the shared preferences file
- Looks for a key named “F2BE6C81-66C8-4763-BDC6-385D39088028”
- If that key exists, and has a value which is itself a list of keys, then it looks for a sub-key called “EnableAddSite”
- If that sub-key exists, and has a value “True,” then the function returns true
Put another way, you need a .mobileconfig profile that includes the following payload:
<key>PayloadContent</key> <array> <dict> <key>DefaultsDomainName</key> <string>com.apple.frontrow</string> <key>DefaultsData</key> <dict> <key>F2BE6C81-66C8-4763-BDC6-385D39088028</key> <dict> <key>EnableAddSite</key> <true/> <key>AddSiteLoggingURL</key> <string>http://my.server.com/log</string> </dict> </dict> </dict> </array>
To load that on the AppleTV, you can either do it the “official” way (the aforementioned method using a USB cable)…or you can do it the easy way. While searching for the AddSite test, I located the code which handles the settings menus, and found functions hidden behind secret sequences of key presses. The trick pertinent to loading a profile is this:
- Start up a simple web server somewhere and put the .mobileconfig file there
- Go to the AppleTV Settings app
- Select “General” then scroll the cursor down to highlight “Send Data To Apple”
- Press “Play” (not the normal “Select” button)
- Enter the URL for the .mobileconfig file (don’t forget to add http://)
- After loading, you may need to restart the AppleTV for the change to take effect
This is much easier than the USB method.
Once you’ve got the Add Site button / app added, then you can add any site you like. You either need to provide a URL to a “Vendor bag” (a configuration file called bag.plist), or a URL to the app’s main “home” screen (plus a name for the app). (Don’t forget to include the “http://” here, too — it will accept a straight hostname without complaint, but then won’t do anything.) A typical bag.plist might look a little like this:
<?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>menu-title</key> <string>My App</string> <key>enabled</key> <string>YES</string> <key>merchant</key> <string>my-app-id</string> <key>root-url</key> <string>http://my.server.com/main.xml</string> <key>menu-icon-url</key> <dict> <key>720</key> <string>http://my.server.com/images/icon720.png</string> <key>1080</key> <string>http://my.server.com/images/icon1080.png</string> </dict> </dict> </plist>
Several of the 3rd party apps added this year have easy-to-discover bag.plist files. You can grab one of those, change the name, point to a different icon, and load it up just to see what it does.
There are a few drawbacks to this trick, though. For example:
- You can’t remove sites you add this way
- It can get a little flaky, especially if there are a lot of sites added which no longer exist (because they were all various tests on different servers, for example)
Also, the logging facility is both a general facility (all apps use it, not just those you’ve manually added) and, in the case of some applications, fairly chatty. It’s possible that one of them might disclose credentials, so don’t point your logs at someone else’s server.
One interesting thing that I noticed just last week: The Add Site application no longer has a blank tile. It’s been replaced with a nice blue button with a big “+” in the middle. This appeared on both a version 5.3 and a jailbroken 5.2 AppleTV. It’s almost like the AppleTV always looked to Apple for an icon, but they never had one ready on the server until recently.
Which brings me to the current state of affairs for this hack: Under the newest version of the AppleTV software (6.0, based on iOS 7.0), this hack breaks. But the functionality is still there — the same keys are in the binary, but the profile no longer enables it. However: it’s not just the AddSite trick that broke, but also the other diagnostic settings I discovered. So I’m hopeful that they’ve just changed the application name or something, so instead of directing the profile to the “com.apple.frontrow” set of shared preferences, perhaps we just change the profile to point to a different address. I’m not sure — I haven’t had much time to play with it.
What I did notice in the 6.0 binary is what appears to be a greatly expanded “Add Site Manager.” Not only can you add new sites, but you can list currently-active sites, and delete sites. And there’s also a mechanism to verify devices for use with a site, perhaps to restrict availability in some way. This new functionality feels a lot like what I’d expect a public “Channel Store” to look like, and I’m really hoping that’s what it’ll be, eventually.
In the meantime, if you have an AppleTV running 5.2 or 5.3, and want to give this a try, it’s pretty easy to get going. I was fortunate enough to have the opportunity to present this hack at DerbyCon 3.0 this weekend, and my slides go into much greater detail as to how this works, and some of the other tricks I found. I’ve put the slides, as well as some really rough code (for the rPI-based server and the “simulator” proxy) on GitHub: Check them out at our github site. There’s also a short video demonstrating this technique with a brand-new AppleTV.
Enjoy, and if you write some cool apps (or better yet, find a way to enable this on AppleTV 6.0), drop me a note!
UPDATE - Oct 3 2013: Well, shoot. It looks like Apple’s disabled the Add Site feature, not just for new versions of the AppleTV software, but for 5.2 and 5.3 as well. I suppose I should have seen this coming — the same mechanism that allowed them to add an icon for the feature last week (probably the box reaching out to Apple) probably has a flag letting them mark the feature as disabled. I guess I should be glad it didn’t happen before my demo on Sunday.
What I didn’t mention in my talk (or maybe I did, I forget — I’d had it on a slide in an earlier draft) was that we did notify Apple of the talk about a month beforehand. There were theoretical (but undemonstrated) security risks associated with the hack. I also wanted Apple to have a chance to warn content providers, in the process of developing apps, that they might want to hide their development servers from public view until they were ready to go live. This seemed the responsible approach to disclosing this research, as my hope was to foster innovation, not to put people or providers at risk.
[As an aside, to those “authorized” developers working on AppleTV apps — I really hope this doesn’t cause too much of a hassle for you guys…and if it does…sorry. Find me at a con and I’ll buy you a beer.]
I’d really hoped that the community could pull together some awesome apps, to demonstrate to Apple just how high the demand for an SDK is. Kind of like what happened when the first iPhone jailbreak happened. I figured the hack would be short-lived, just not so much so. On the other hand, before Sunday, very few people even knew this feature existed. Until now, we all thought the only way to get an app on the AppleTV was with a jailbreak. Now there’s another target for the jailbreaking community to go after, and I hope they do so. There’s gotta be a way to re-enable this.
So, anyway, sorry to have given everyone hope only to have it yanked away so quickly. But again…maybe there’s a fix. If this can be re-enabled more easily than a full-blown jailbreak, then perhaps there’s still hope for people to develop their own AppleTV applications. If anyone figures it out, you know I’ll be tweeting about it, and getting back to work on my own apps. But until then, thanks to everyone for the kind words about this post and my talk. It was definitely a fun ride!
UPDATE - Oct 4 2013: Shortly after this post originally went live, Aman Gupta (@tmm1) reached out to me to begin speculation on how this could be fixed for ATV 6.0. Then early yesterday, he broke the news to me that Apple had disabled Add Site for ATV 5.2 and 5.3. He’s not stopped poking at the problem, though, and after an all-nighter with a jailbroken device and CyCript, he pinpointed how Apple disabled the feature.
When the AppleTV application starts up, it reaches out to Apple to collect information about all the “standard” applications. One of the apps returned is “internet-add-site.” The information is returned in roughly the same format as the bag.plist files we’ve been working with, and this is where Apple recently added a link for the Add Site icon. Well, they added the following property/value:
The bad news is that, it appears because of this change, the AppleTV won’t even try to add the Add Site button. It won’t even check whether it’s enabled. I still have one last slim possibility to investigate, but it looks like they’ve effectively broken this for old devices.
The good news is that they didn’t add anything new or convoluted — so hopefully, if we can figure out how to re-enable the profile changes that enabled Add Site to begin with, it should be able to work with 6.0. But that’s still a ways off (and might need to wait until an ATV 6.0 jailbreak happens…)
Amusingly, though…we were able to get the Add Site back on a jailbroken device. The file at
/User/Library/Application Support/Front Row/ExtraInternetCategories.plist contains a list of extra sites that were added. I suggested that Aman take the data he intercepted, put it into a new bag.plist on a local server (while stripping the minimum-required-version key), and put a pointer to that bag in the ExtraInternetCategories file. He did that, and bingo, the button came back.
Of course, if you can do this, then you don’t need the Add Site button anyway — just add sites directly to the ExtraInternetCategories file. Here’s a full file, accessing a single site:
<?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"> <array> <dict> <key>Name</key> <string></string> <key>URL</key> <string>http://my.server.com/bag.plist</string> </dict> </array> </plist>
Just add additional <dict> blocks for each external bag.plist you want to include.
But really, that’s just a hack for people with jailbroken devices. The goal of making this available to everyone still depends on finding the trick for ATV 6.0, and that will probably still take a while…