Dump decrypted mach-o apps

Posted: August 4th, 2016 | Author: | Filed under: code injection, DYLD_INSERT_LIBRARIES, macOS, Programming | Tags: , , , , , , , , | 4 Comments »

 
In a previous post “CryptedHelloWorld: App with encrypted mach-o sections”, I created a simple macOS app ‘CryptedHelloWorld’ with its (__TEXT, __text) section encrypted. The section is decrypted by a constructor function.

 
This post explains how to dump the decrypted app. A common way is to attach the app with a debugger (GDB, LLDB) and manually dump the decrypted memory to disk.

However I will use a different solution by using 2 techniques already presented in previous posts: a destructor function and code injection.

The targeted app is the precompiled CryptedHelloWorld command line tool that can be downloaded here.

This command line tool has its (__TEXT, __text) section encrypted. Once its main() function is called, we know that the section is decrypted. Thus we can create a destructor function – which is called just before the app is quit – to dump the decrypted memory to disk. This destructor function will be injected into the app using the DYLD_INSERT_LIBRARIES environment variable.

The destructor function needs to read the executable from disk, dump the decrypted (__TEXT, __text) section and replace the encrypted bytes by the decrypted bytes.

 
 
Code injection

I already described how to inject code using DYLD_INSERT_LIBRARIES in this post. We will use the exact same technique by building a dynamic library like this:

gcc -o DumpBinary.dylib -dynamiclib DumpBinary.c

and then run it using the DYLD_INSERT_LIBRARIES environment variable:

DYLD_INSERT_LIBRARIES=./DumpBinary.dylib ./CryptedHelloWorld

 
 
Destructor function

Creating a destructor function has been described in this post. Such a function will be called just before the app quits:

void __attribute__((destructor)) DumpBinaryDestructor()
{
     // Executed just before the app quits
}

 
 
Finding the targeted app mach-o header

The first problem to solve is to find the mach-o header of the targeted app. This is easily done using the dyld function _dyld_get_image_header and searching for the first image of type MH_EXECUTE:


//
// Find the main executable
//
const struct mach_header_64 *machHeader = NULL;

for(uint32_t imageIndex = 0 ; imageIndex < _dyld_image_count() ; imageIndex++)
{
	const struct mach_header_64 *mH = (const struct mach_header_64 *)_dyld_get_image_header(imageIndex);
	if (mH->filetype == MH_EXECUTE)
	{
		const char* imageName = _dyld_get_image_name(imageIndex);
		fprintf(stderr, "Found main executable '%s'\n", imageName);
		
		machHeader = mH;
		break;
	}
}

 
 
Finding the executable path on disk

The dynamic library will need to read the app binary from disk: it needs the executable path. This is done using the dyld function _NSGetExecutablePath which copies the path of the main executable into a buffer:


//
// Get the real executable path
//
char executablePath[PATH_MAX];

/*
_NSGetExecutablePath() copies the path of the main executable into the
 buffer buf.  The bufsize parameter should initially be the size of the
 buffer.  This function returns 0 if the path was successfully copied, and
 * bufsize is left unchanged.  It returns -1 if the buffer is not large
 enough, and * bufsize is set to the size required.  Note that
 _NSGetExecutablePath() will return "a path" to the executable not a "real
 path" to the executable.  That is, the path may be a symbolic link and
 not the real file. With deep directories the total bufsize needed could
 be more than MAXPATHLEN.
*/
uint32_t len = sizeof(executablePath);
if (_NSGetExecutablePath(executablePath, &len) != 0)
{
	fprintf(stderr, "Buffer is not large enough to copy the executable path\n");
	exit(1);
}

We then get the canonical path using realpath:



//
// Get the canonicalized absolute path
//
char *canonicalPath = realpath(executablePath, NULL);
if (canonicalPath != NULL)
{
	strlcpy(executablePath, canonicalPath, sizeof(executablePath));
	free(canonicalPath);
}

 
 
Reading from disk

Reading from disk is done using fopen/fread:


//
// Open the executable file for reading
//
FILE *sourceFile = fopen(executablePath, "r");
if (sourceFile == NULL)
{
	fprintf(stderr, "Error: Could not open executable path '%s'\n", executablePath);
	exit(1);
}

//
// Read the source file and store it into a buffer
//
fseek(sourceFile, 0, SEEK_END);
long fileLen = ftell(sourceFile);
fseek(sourceFile, 0, SEEK_SET);

uint8_t *fileBuffer = (uint8_t *)calloc(fileLen, 1);
if (fileBuffer == NULL)
{
	fprintf(stderr, "Error: Could not allocate buffer\n");
	exit(1);
}

if (fread(fileBuffer, 1, fileLen, sourceFile) != fileLen)
{
	fprintf(stderr, "Error: Could not read the file '%s'\n", executablePath);
	exit(1);
}

 
 
Finding the (__TEXT, __text) and (__DATA, __mod_init_func) sections

We already have the mach-o header. We need to loop through all segments and sections until we find the interesting sections:


//
// Loop through each section
//
size_t segmentOffset = sizeof(struct mach_header_64);

for (uint32_t i = 0; i < machHeader->ncmds; i++)
{
	struct load_command *loadCommand = (struct load_command *)((uint8_t *) machHeader + segmentOffset);
	
	if(loadCommand->cmd == LC_SEGMENT_64)
	{
		// Found a 64-bit segment
		struct segment_command_64 *segCommand = (struct segment_command_64 *) loadCommand;

		// For each section in the 64-bit segment
		void *sectionPtr = (void *)(segCommand + 1);
		for (uint32_t nsect = 0; nsect < segCommand->nsects; ++nsect)
		{
			struct section_64 *section = (struct section_64 *)sectionPtr;
			
			fprintf(stderr, "Found the section (%s, %s)\n", section->segname, section->sectname);
			
			if (strncmp(segCommand->segname, SEG_TEXT, 16) == 0)
			{
				if (strncmp(section->sectname, SECT_TEXT, 16) == 0)
				{
					// This is the (__TEXT, __text) section.

				}
			}
			else if (strncmp(segCommand->segname, SEG_DATA, 16) == 0)
			{
				if (strncmp(section->sectname, "__mod_init_func", 16) == 0)
				{
					// This is the (__DATA, __mod_init_func) section.

				}
			}
			
			sectionPtr += sizeof(struct section_64);
		}
	}
	
	segmentOffset += loadCommand->cmdsize;
}



 
 
Dumping the decrypted (__TEXT, __text) section

We just use a simple memcpy to replace in the buffer the encrypted bytes by the decrypted bytes:

fprintf(stderr, "\t Save the unencrypted (%s, %s) section to the buffer\n", section->segname, section->sectname);
memcpy(fileBuffer + section->offset, (uint8_t *) machHeader + section->offset, section->size);

 
 
Removing the constructor function

We now have a decrypted binary. However if we launch it, its constructor function will be called and corrupt the (__TEXT, __text) section. We need to prevent the constructor function to be executed. There are several solutions and I chose to zero out the (__DATA, __mod_init_func) section. I kept the segname and sectname info so that MachOView can nicely display it.


fprintf(stderr, "\t Zero out the (%s, %s) section\n", section->segname, section->sectname);

size_t sectionOffset = sectionPtr - (void *)machHeader;

// Size of char sectname[16] + char segname[16]
size_t namesSize = 2 * 16 * sizeof(char);

// Zero out the section_64 but keep the sectname and segname
bzero(fileBuffer + sectionOffset + namesSize, sizeof(struct section_64) - namesSize);

 
 
Writing the decrypted binary to disk

The last step consists of writing the decrypted app to disk. This is done with fwrite:


//
// Create the output file
//
char destinationPath[PATH_MAX];
strlcpy(destinationPath, executablePath, sizeof(destinationPath));
strlcat(destinationPath, "_Decrypted", sizeof(destinationPath));

FILE *destinationFile = fopen(destinationPath, "w");
if (destinationFile == NULL)
{
	fprintf(stderr, "Error: Could create the output file '%s'\n", destinationPath);
	exit(1);
}

//
// Save the data into the output file
//
if (fwrite(fileBuffer, 1, fileLen, destinationFile) != fileLen)
{
	fprintf(stderr, "Error: Could not write to the output file\n");
	exit(1);
}


 
 
Log output

To run the CryptedHelloWorld app and inject our code:

DYLD_INSERT_LIBRARIES=./DumpBinary.dylib ./CryptedHelloWorld

Here is the log output when running the CryptedHelloWorld:


*** Constructor called to decrypt sections
Found the section (__TEXT, __text)
Decrypting the (__TEXT, __text) section
Found the section (__TEXT, __stubs)
Found the section (__TEXT, __stub_helper)
Found the section (__TEXT, __timac)
Found the section (__TEXT, __cstring)
Found the section (__TEXT, __unwind_info)
Found the section (__DATA, __nl_symbol_ptr)
Found the section (__DATA, __got)
Found the section (__DATA, __la_symbol_ptr)
Found the section (__DATA, __mod_init_func)
Found the section (__DATA, __data)
Found the section (__DATA, __bss)
*** The sections should now be decrypted. main() will be called soon.


------------------
Hello, World!
------------------


*********************************
*** DumpBinaryDestructor CALLED
*********************************
Found main executable '/CryptedHelloWorld/DumpBinary/./CryptedHelloWorld'
Found absolute path: '/CryptedHelloWorld/DumpBinary/CryptedHelloWorld'
Found the section (__TEXT, __text)
	 Save the unencrypted (__TEXT, __text) section to the buffer
Found the section (__TEXT, __stubs)
Found the section (__TEXT, __stub_helper)
Found the section (__TEXT, __timac)
Found the section (__TEXT, __cstring)
Found the section (__TEXT, __unwind_info)
Found the section (__DATA, __nl_symbol_ptr)
Found the section (__DATA, __got)
Found the section (__DATA, __la_symbol_ptr)
Found the section (__DATA, __mod_init_func)
	 Zero out the (__DATA, __mod_init_func) section
Found the section (__DATA, __data)
Found the section (__DATA, __bss)
*********************************
*** Decryption completed
*********************************

 
 
Examining the decrypted app

Using MachOView, we see that the (__TEXT, __text) section is decrypted:


(__TEXT, __text)

 

We also see that the (__DATA, __mod_init_func) has been zeroed out:


(__DATA, __mod_init_func)

 
 
Limitations of the dynamic library

  • it only supports 64-bit intel Mach-O files. Adding 32-bit, ARM or fat Mach-O support is fairly simple and left to the reader.
  • it only dumps the (__TEXT, __text) section.
  • it zeroes out the (__DATA, __mod_init_func) section which would cause problems if there are multiple constructors.

 
 
Downloads

The dynamic library source code can be downloaded here.

The precompiled dynamic library can be downloaded here.


constructor and destructor attributes

Posted: July 16th, 2016 | Author: | Filed under: code injection, Debugging, macOS, Programming | Tags: , , , , , , | 3 Comments »

GCC (and Clang) supports constructor and destructor attributes:

__attribute__((constructor))
__attribute__((destructor))

 
 
Description

A function marked with the __attribute__((constructor)) attribute will be called automatically before your main() function is called. Similarly a function marked with the __attribute__((destructor)) attribute will be called automatically after your main() function returns.

You can find the GCC documentation here:

constructor
destructor
The constructor attribute causes the function to be called automatically before execution enters main (). Similarly, the destructor attribute causes the function to be called automatically after main () has completed or exit () has been called. Functions with these attributes are useful for initializing data that will be used implicitly during the execution of the program.
These attributes are not currently implemented for Objective C.

Note: The GCC documentation tells that these attributes are not implemented for Objective-C. However this seems to work as expected with my tests using Clang ‘clang-703.0.31’ from Xcode 7.3.1.

 
 
Example

Here is an example of C code to demonstrate these attributes:


//
// To compile:
// clang -o constructor constructor.c
//

#include <stdio.h>
 
void constructor() __attribute__((constructor));
void destructor() __attribute__((destructor));

int main()
{
	printf ("main called\n");
	return 0;
}

void constructor()
{
	printf ("constructor called\n");
}

void destructor()
{
	printf ("destructor called\n");
}

When running this application, you will see the following output logs as you would expect:

constructor called
main called
destructor called

 
 
How does it work under the hood?

When you mark functions with these attributes, the compiler will create in your binary the sections called __mod_init_func for the constructors and __mod_term_func for the destructors. These sections contain the list of function pointers. You can use the excellent MachOView to see these sections:


ACTION

When your application is launched, dyld will call the constructors before your main() function is called. This is handled by the following dyld function:

void ImageLoaderMachO::doModInitFunctions(const LinkContext& context)

The destructors are handled by the dyld function:

void ImageLoaderMachO::doTermination(const LinkContext& context)

Since dyld is open source you can look at the implementation in the file ImageLoaderMachO.cpp of dyld. The source code for macOS 10.11.4 is available here.

 
 
Example of use

  • The first obvious usage is to be able to initialize some global variables with a constructor and do some cleanup with a destructor. It could be used to initialize some libraries too.
  •  

  • Another usage is code injection. In a previous post ‘Simple code injection using DYLD_INSERT_LIBRARIES’ I wrote code to replace some methods with an Objective-C +(void)load class method. Using a constructor would allow to inject code earlier in the process.
  •  

  • A constructor attribute could be used to implement a software protection. You could encrypt your executable with a custom encryption and use a constructor function to decrypt the binary just before it is loaded.

Disable swipe to delete in Mail.app on OS X 10.11

Posted: May 10th, 2016 | Author: | Filed under: code injection, macOS, Mail | 18 Comments »

OS X 10.11 ‘El Capitan’ added a new feature to Mail.app ‘Swipe to manage your inbox’:

Swipe to manage your inbox.
Now you can take care of your email with a swipe, just like on your iOS devices. Need to triage your inbox? Swipe right to mark an email as read or unread, or swipe left to delete. You’ll be focused on what’s important in no time.


Swipe To Delete

 

I find this new feature extremely annoying as I keep triggering it by accident. Sadly it seems that there is no preference (even secret preference) to disable this feature. But the good news is that Mail.app supports plugins.

To disable this feature, I created a simple Mail.app plugin. A precompiled version for Mail 9.3 (3124)
(OS X 10.11.4) can be downloaded here: DisableSwipeGesture.mailbundle.zip

 

You can download the source code here : Download ‘DisableSwipeGesture’ Source Code

 

Installation using the precompiled version for Mail 9.3 (3124) – OS X 10.11.4:

  • Download the precompiled version
  • Unzip
  • Copy the file into ~/Library/Mail/Bundles/
  • Relaunch Mail.app

 

Installation for other versions of Mail.app:

  • Download the DisableSwipeGesture source code
  • Open the project in Xcode
  • Build
  • Relaunch Mail.app

 

How does it work?

Mail.app uses a standard NSTableView to support the swipe to delete gesture. It implements the AppKit -tableView:rowActionsForRow:edge: delegate method to add the swipe to delete feature.

Before handling a swipe event, AppKit checks if swipe to delete is supported with the internal method -(BOOL)[NSTableView _allowSwipeToDeleteForEvent:]. The default implementation checks if the NSTableView is a view based tableview and if there is a delegate. The ‘DisableSwipeGesture’ Mail plugin overrides this internal method to always return NO i.e. to never allow swipe to delete. Note that this plugin only changes the behavior of Mail.app, it does not affect any other app. However the same mechanism could be used to disable the swipe to delete feature for any OS X app supporting plugins.

 

Mail.app plugin compatibility

Before loading any plugin, Mail.app checks if the plugin’s Info.plist contains the current Mail.app ‘PluginCompatibilityUUID’ value. If this is not the case, Mail.app will refuse to load the plugin and you will see an alert:


Incompatible Plugin

If you use this ‘DisableSwipeGesture’ plugin and you update Mail.app though an OS X update, you will need to update the PluginCompatibilityUUID value in the Info.plist of the ‘DisableSwipeGesture’ plugin. The simplest solution is to recompile the plugin using the steps provided in ‘Installation for other versions of Mail.app’. The Xcode project has a build phase that will extract the PluginCompatibilityUUID from /Application/Mail.app and copy it into the Info.plist.


Simple code injection using DYLD_INSERT_LIBRARIES

Posted: December 18th, 2012 | Author: | Filed under: code injection, Debugging, DYLD_INSERT_LIBRARIES, macOS, Programming | 15 Comments »

In the following article I will describe a simple method to inject code into executables on Mac OS X 10.8 using the DYLD_INSERT_LIBRARIES environment variable.
I also wrote a simple launcher that starts Calculator.app and injects code to modify the About Box of Calculator.app. When bringing the About Box window of Calculator.app, a custom alert will be displayed:

Modifying Calculator.app AboutBox to display a custom alert

Note: Code injection should be used with care. You should probably not ship applications using code injection and the discussed environment variable DYLD_INSERT_LIBRARIES.

On Mac OS X 10.8, there are several ways to inject code into an arbitrary 64-bit process:

  • writing a plugin if the targeted application supports plugins. Such a solution is possible for applications like Safari, Mail, Xcode… but not for the Calculator.app.
  • Injecting code through Scripting Additions: you create a daemon to watch the launch of the targeted application and this daemon sends a custom Apple event to trigger the code injection. This solution is apparently used by 1Password 3.
  • you can inject code using Mach ports by using mach_override and mach_inject but it has some downsides (you need to be in the procmod group or root).
  • Injecting code through a kernel extension: This is really powerful but the code runs in the kernel.
  • Modifying the binary of the application but this can’t be reused and you need to reapply the changes for each new version of the application.
  • Injecting code using the DYLD_INSERT_LIBRARIES environment variable: this is a really simple solution to implement but you can only inject code in the application you launch.

Now that we know the different ways for injecting code, let’s look more in details at the DYLD_INSERT_LIBRARIES environment variable.

Using DYLD_INSERT_LIBRARIES has several advantages:

  • It is simple to implement.
  • All the code runs in userland and you don’t need to be root or run with the procmod group.
  • You don’t rely on complex third party code.
  • It can be used to inject code in any application you start.
  • You only inject code in a specific application.

It has some downsides:

  • You can only inject code in the applications you start.

On Mac OS X, the dynamic linker (dyld) can be used to load a dynamic library specified in the DYLD_INSERT_LIBRARIES environment variable into an executable. I created a simple dynamic library that replaces the -[CalculatorController showAbout:] method of Calculator.app with a custom implementation. Following is the code of the dynamic library (ACCalculatorOverrides.m). Here is what it does:

  • I created an object called ACCalculatorOverrides with a +(void)load class method. This code is invoked really early by the runtime. It exchanges the implementation of the method -[CalculatorController showAbout:] by the implementation of -[ACCalculatorOverrides patchedShowAbout:].
  • The method -[ACCalculatorOverrides patchedShowAbout:] will call the original method to display the original About Box and then display a custom alert.

#import "ACCalculatorOverrides.h"

#include <stdio.h>
#include <objc/runtime.h>
#include <Foundation/Foundation.h>
#include <AppKit/AppKit.h>

static IMP sOriginalImp = NULL;

@implementation ACCalculatorOverrides

+(void)load
{
	// We replace the method -[CalculatorController showAbout:] with the method -[ACCalculatorOverrides patchedShowAbout:]
	Class originalClass = NSClassFromString(@"CalculatorController");
	Method originalMeth = class_getInstanceMethod(originalClass, @selector(showAbout:));
	sOriginalImp = method_getImplementation(originalMeth);
	
	Method replacementMeth = class_getInstanceMethod(NSClassFromString(@"ACCalculatorOverrides"), @selector(patchedShowAbout:));
	method_exchangeImplementations(originalMeth, replacementMeth);
}

-(void)patchedShowAbout:(id)sender
{
	// We first call the original method to display the original About Box
	sOriginalImp(self, @selector(showAbout:), self);
	
	// Run our custom code which simply display an alert
	NSAlert *alert = [NSAlert alertWithMessageText:@"Code has been injected!" defaultButton:@"OK" alternateButton:nil otherButton:nil informativeTextWithFormat:@"The code has been injected using DYLD_INSERT_LIBRARIES into Calculator.app"];
	[alert runModal];
}

@end

It is possible to manually build this dynamic library by running in the Terminal:

gcc -framework AppKit -framework Foundation -o CalculatorOverrides.dylib -dynamiclib ACCalculatorOverrides.m

and manually injecting it into Calculator.app by running in the Terminal:

DYLD_INSERT_LIBRARIES=/PATH_TO/CalculatorOverrides.dylib /Applications/Calculator.app/Contents/MacOS/Calculator &

But to make it simpler to use, let’s write a launcher. The launcher will be a background-only application (LSUIElement set to YES) that will execute the previously mentioned command line and then quit itself. Here is the code of the launcher:


#import "AppDelegate.h"

@implementation AppDelegate

- (void)dealloc
{
    [super dealloc];
}

-(void)bringToFrontApplicationWithBundleIdentifier:(NSString*)inBundleIdentifier
{
	// Try to bring the application to front
	NSArray* appsArray = [NSRunningApplication runningApplicationsWithBundleIdentifier:inBundleIdentifier];
	if([appsArray count] > 0)
	{
		[[appsArray objectAtIndex:0] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
	}
	
	// Quit ourself
	[[NSApplication sharedApplication] terminate:self];
}

-(void)launchApplicationWithPath:(NSString*)inPath andBundleIdentifier:(NSString*)inBundleIdentifier
{
	if(inPath != nil)
	{
		// Run Calculator.app and inject our dynamic library
		NSString *dyldLibrary = [[NSBundle bundleForClass:[self class]] pathForResource:@"CalculatorOverrides" ofType:@"dylib"];
		NSString *launcherString = [NSString stringWithFormat:@"DYLD_INSERT_LIBRARIES=\"%@\" \"%@\" &", dyldLibrary, inPath];
		system([launcherString UTF8String]);
		
		// Bring it to front after a delay
		[self performSelector:@selector(bringToFrontApplicationWithBundleIdentifier:) withObject:inBundleIdentifier afterDelay:1.0];
	}
}

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
	NSString *calculatorPath = @"/Applications/Calculator.app/Contents/MacOS/Calculator";
	if([[NSFileManager defaultManager] fileExistsAtPath:calculatorPath])
		[self launchApplicationWithPath:calculatorPath andBundleIdentifier:@"com.apple.calculator"];
}

@end

Download: You can download here the compiled Calculator Launcher. If you launch it, it will launch the Calculator.app and inject the code to display an alert when you display the About Box of Calculator.app. If you are interested by the source code, the full sources are available here.