11

This one is probably a lost cause, but I'll ask cause I'm honestly just curious...

We have a client that wants to create a replacement Messaging app for OS X. They basically want to use the same accounts, chat history, and everything, but provide a completely different UI (for people with certain disabilities) to the built-in Messages.app. Creating their very own messaging app would not fly given that the primary service in Messages.app, iMessage, is completely undocumented and so supporting that with 3rd party code would be nearly impossible.

Upon initial research, it became obvious that the well-documented AppleScript approach would provide a workable but crude solution, missing many features from the original app (such as an indication while typing, etc.), not to mention that it requires keeping the original Messages app running which is distracting to the user.

At that point we started digging a little deeper and found the IMCore.framework. IMCore is basically what Messages.app uses to communicate with the various services, and its engine is imagent, which is what appears to manage the data, and actually communicate with the various IM servers. IMCore is a private framework which obviously is somewhat risky to use (and automatically excludes their app from the App Store), but our assumption was that with OS X we should still be able to implement this and distribute the application outside of the App Store with not much difficulty.

We started experimenting with IMCore (while reverse-engineering Messages.app to see how it's used), and made some headway. We were able to successfully connect to the imagent process and perform several configuration operations, but then discovered that the data model is basically empty -- we're not able to see any of the user's data or communicate with any IM services even though we're running in the user's security context.

Then we noticed that the Messages.app has some very curious undocumented entitlements such as com.apple.private.imcore.imdpersistence.database-access and com.apple.imagent. At this point we're assuming that these entitlements are what we're missing in order to successfully communicate with imagent. We've tried adding those entitlements to our own app and were able to successfully build and codesign it, but when the program is launched it crashes on startup with the system message EXC_CRASH (Code Signature Invalid) (Xcode says Terminated due to code signing error).

Our fearful assumption is that Apple locked their private entitlements so that the system won't accept a binary that uses them unless it is signed directly by Apple, but this is obviously a theory. The other question is, how does imagent know whether our binary has these entitlements or not? Couldn't we somehow spoof these entitlements?

As I said, feels like a lost cause but who knows. I'm guessing people who have done hardcore jailbreak work on iOS might have an idea or two -- anyone?

ldoogy
  • 2,819
  • 1
  • 24
  • 38
  • 1
    You're probably better off looking at Hackintosh information than iOS jailbreak info for this. Have you tried using a root-trusted code signing certificate? [Here is some information on creating one](https://sourceware.org/gdb/wiki/BuildingOnDarwin). – Alexander O'Mara Feb 25 '15 at 04:57
  • Good point Alexander. Added Hackintosh tag. Haven't tried a root-trusted cert, might be worth a shot. – ldoogy Feb 25 '15 at 05:02
  • 1
    Speculation, but worth considering: It is very likely that Apple has intentionally locked down Messages access quite heavily to prevent malicious applications from reading or sending messages. Remember: if your application can do it, *any* application can do it. –  Feb 25 '15 at 05:18
  • Interesting, using a root-trusted cert actually allows us to run it with the private entitlements, but the accounts and services are still nowhere to be found. It's possible that the problem actually lies elsewhere. duskwuff, I completely agree that they are likely to lock it down, and that it would make a lot of sense for them to do so. – ldoogy Feb 25 '15 at 19:06
  • 1
    Correction: Using a root-trusted cert does NOT allow us to run with the private entitlements. We saw that imagent was reporting that it was not granting the listener port because our process was not entitled. Embarrassingly, it was determined that our manual code signing for the root-trusted cert was failing to include the entitlements file... Anyway, once we added it, we got the following onerous message: taskgated[78]: killed com.foo.bar [pid 31373] because its use of the com.apple.imagent.av entitlement is not allowed (error code -67050). Sounds like this is the end of the road? – ldoogy Feb 28 '15 at 07:31
  • You should specify whether your client requires this app to be built for all iOS devices, or is willing to accept the requirement to jailbreak their devices. This matters. – Nate Mar 09 '15 at 11:09
  • It's not for iOS, it's for OS X. I mentioned iOS because we believe that entire infrastructure is very similar between those two systems, so were hoping that someone who has done jailbreak iOS hacking will know how this works. – ldoogy Mar 23 '15 at 22:18

1 Answers1

10

I'm going to answer my own question to provide a bit more information in case anyone cares about this. At the end of the day we were able to cross this barrier by injecting into the imagent process and trapping the entitlement verification functions, adding functionality so that imagent will allow the XPC connection for our client.

This opened the door to full, unlimited communications with imagent through IMCore.framework, and I can confirm that full iMessage functionality was achieved. We we were able to see the user's iTunes account, send and receive messages, load messages from the user's database (to show the history for each chat), and pretty much everything else. The implementation included a tiny system daemon that injected imagent whenever it was restarted (or when the system booted up), so it was very easy for an end-user to install using a standard OS X installer program.

IMCore.framework is fairly easy to use and includes every tiny bit of metadata for iMessage, including notifications that the user on the other end is typing, the APIs for the sending and receiving of attachments, you name it! It seems to change a bit between OS X releases, but we were able to make it work across OS X versions (we tested 10.8 through 10.10).

The challenge came when El Capitan showed up. The new rootless feature (System Integrity Protection) in El Capitan prevents from injecting our little hack into imagent, which put an end to this solution. :-( The failure happens when we call task_for_pid on the imagent process. That fails and basically blocks us from injecting our code into that process.

So overall not a happy ending, but at least we got a taste of the promised land.

ldoogy
  • 2,819
  • 1
  • 24
  • 38
  • Yeah, `task_for_pid` fails on OS X system binaries in 10.11 unless you disable SIP. You might be able to get around this using a kernel extension, but it would need to be signed with a kext certificate from Apple (unless SIP is disabled). – Alexander O'Mara Feb 08 '16 at 23:15
  • @AlexanderO'Mara, in this case asking users to disable SIP is not very practical (not to mention that it also somewhat compromises them). It is likely possible to circumvent this through a kext, but Apple won't grant us one. We asked and they said that this whole thing is unsupported (even if it's a legitimate, sensible use case). – ldoogy Feb 09 '16 at 00:17
  • Could you go into more detail on how this was achieved? I'm trying to build an iMessage proxy (to get iMessage cross-platform) and am also looking to break free from applescript. Do we simply need to add the entitlements, fork ourself as 0, and roll? – Allison Jan 28 '17 at 07:38
  • Shoot me an email at my user name at gmail and I'll try to help. – ldoogy Jan 30 '17 at 23:59