Herein lies madness

Mac OS X code injection

Code injection on Mac OS X is possible via mach_star package which consists of two functions, mach_override (replace or extend existing functions at runtime) and mach_inject (dynamically load your code into a running process). An Intel port is available here.

mach_star

While the example provided in the mach_star package worked out of the box (if I recall correctly), I wanted to create a project that didn't rely on XCode and the Carbon API. In order to get that to work, I had to add MAP_SHARED to the mmap call in mach_inject.c:

char * fileImage = mmap (NULL, mapSize, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);

Loader bundle

Following the layout of the provided example, the idea is to inject just enough code to load a bundle in the targeted running application. Once the injected bundle is loaded, the environment should then be stable and we can proceed to override existing functions in the application. So we create a loader bundle loader.dylib which consists of:

void *pthread_entry(void *patch_bundle)
{
	void *bundle = dlopen((char *)patch_bundle, RTLD_NOW);
	if (!bundle)
		fprintf(stderr, "Could not load patch bundle: %s\n", dlerror());
	return 0;
}

void inject_entry(ptrdiff_t offset, void *param, size_t psize, void *dummy)
{
	extern void __pthread_set_self(void *);

	__pthread_set_self(dummy);

	pthread_attr_t attr;
	pthread_attr_init(&attr); 
	
	int policy;
	pthread_attr_getschedpolicy(&attr, &policy);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
	pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
	
	struct sched_param sched;
	sched.sched_priority = sched_get_priority_max(policy);
	pthread_attr_setschedparam(&attr, &sched);

	pthread_t thread;
	pthread_create(&thread, &attr,
			(void * (*)(void *))((long)pthread_entry),
			(void *)param);
	pthread_attr_destroy(&attr);
	
	thread_suspend(mach_thread_self());
}

This loader.dylib bundle is then loaded by my application and injected into the targeted application using mach_inject with the name of the bundle we wish load inside the targeted application as a parameter.

Patch bundle

A new bundle patch.dylib that will be loaded inside the targeted application is created, which in part consists of:

void install(void) __attribute__ ((constructor));

void install()
{
	// .. 
}

The constructor function attribute ensures that the install function is called automatically when patch.dylib is loaded. We now have a sane environment and can proceed to wreck chaos in the targeted application. Enter mach_override:

typedef void (*override_fn)(void);
override_fn orig_fn;

void install()
{
	if (mach_override("_override_fn", NULL, patch_fn, (void **) &orig_fn) != 0)
		fprintf(stderr, "mach_override failed\n");
}

In the above piece of code, we override the function override_fn with our own patch_fn function. A pointer to the original override_fn is stored in the orig_fn variable. And we are done.

No news ...

.. is good news

Categories