PDA

View Full Version : Executing binaries with objective-c




chris27uk
Apr 13, 2009, 10:30 AM
Hi there,

I need a bit of advise on executing applications from a cocoa application written in objective-c.

To put this in context, I am a fairly experienced programmer in my usual field which is java/c/c++/.net. So I have very little experience with developing on the Macintosh platform although I am fairly familliar with the platform. I have had less than 50 hours to get up to scratch with objective-c and so forgive me if my question has misconceptions.

I (think) I need to execute a binary from an application bundle in memory. i.e. I have a set of binary (byte) data which represents an executable and I want to execute this without writing it to disk.

The reason I need to do this, is we have an executable which we do not want the user being able to execute or transfer from the network themselves.

I have had a look at NSTask and this only seems to allow the execution of a binary from disk. Is there any way to execute from memory (i.e. a stream reader or similar)?

If not, could this be achieved by using an encrypted disk image? Can you access the data from an encrypted disk image without mounting the disk image and being transparent to the user?

Any help, pointers or guidance would be very appreciated,
Many Thanks,
Chris.



lee1210
Apr 13, 2009, 11:06 AM
exactly how careful do you need to be about the availability of this thing? Are your users technical and known to be malicious, or do you just want to prevent casual access to this binary? Do you have the source for this thing such that it could simply be made a subroutine that you can call within the new program?

The answers to these will have a big impact on how you implement this. I would say that you could write the file to a temporary location, exec it (via system(), NSTask, etc.), and remove the binary as soon as the exec occurs. The inodes will still point to the data, and the reference count will stay 1 as long as the program is executing, but once it stops it will be "gone" from the filesystem, and without heroics the user couldn't access this file through the filesystem after you've removed it.

-Lee

chris27uk
Apr 13, 2009, 11:17 AM
Unfortunately, the users are likely to be highly motivated to try and nick the software and so I'd really like to get around saving temporary files, although the solution you suggest doesn't sound too bad.

The users pay for the software and any loss of the application would mean us ultimately paying fines (while fairly small, this isn't too good.)

I dont have the source the software as it can be a wide range of software. Apart from having an OSX compatible binary, thats all I've got.

WhiteRabbit
Apr 13, 2009, 01:06 PM
Is your application something along the lines of Steam? I myself don't know how it works, I imagine that the "protected" application itself is designed to authenticate with Steam, and that Steam is not just a simple wrapper that encrypts the application.

Krevnik
Apr 13, 2009, 02:51 PM
Is your application something along the lines of Steam? I myself don't know how it works, I imagine that the "protected" application itself is designed to authenticate with Steam, and that Steam is not just a simple wrapper that encrypts the application.

Basically, that is what Steam does.

There are many problems with trying to encrypt and run arbitrary binaries. Especially since on OS X, a raw binary is usually assumed to be part of a bundle, and will access the bundle in ways you can't predict. Therefore, the bundle resources need to be on disk somewhere, and unencrypted. The moment you can use NSBundle to get a file, so can a user on the filesystem.

You'd have to write an encryption shim that loads the encrypted binary, decrypts it in RAM, and jumps into the entry point using assembler. Although your resource blobs are still in the clear.

You would need to look at the APIs that let you load and manipulate Mach-O binaries to do such a thing.

The more secure route will require middleware (that you write) which interacts with the service, validates the license, and decrypts the binary, and the data assets (wrapping around the normal loading methods). If the authors of the apps want to distribute independent of your service as well, then you will also need a stub version of the middleware that they can compile into the app which doesn't actually integrate with the service.

EDIT: I personally would rather go the route of shimming the app, as it gives the user a double-clickable icon to launch the app. Requiring a user to launch your service in order to launch the app is not a good user experience. Also, you have to assume that: A) resources and other data need to be on the filesystem for an OS X app to run, thus exposing them to attack, and B) The user will be able to figure out where you hide any data, including encrypted disk images, and will thus be able to gain access. If the apps you are accessing via the service can run unchanged, then a user will be able to figure out where it is hiding and gain access to the unencrypted binary and resource data.

Thus, it seems to me that letting the app 'hang out' on the filesystem is going to happen anyways, so let the user see it, and secure the code/data via some other means.

chris27uk
Apr 13, 2009, 05:40 PM
You'd have to write an encryption shim that loads the encrypted binary, decrypts it in RAM, and jumps into the entry point using assembler. Although your resource blobs are still in the clear.

This seems like the best suggestion, as I really don't want to restrict myself to requiring the applications to implement arbitrary authentication code. While I understand Steam is not a simple wrapper, keeping the system as usable as possible with our current apps is important.

I'm really appreciative of all the help I've got, thanks a lot for spending some of your time to reply. Its given me a better idea of what I need to be doing and the compromises.