views:

378

answers:

1

Hello, my fellow developers! I hope very much that at least some of you will not get frightened by the amount of text this question contains (I simply did my best to be as descriptive as humanely possible). :)

To those who think I've asked this question to write malware or something. I want to write an application that will allow users to select applications to be launched after the OS will finish launching. The whole idea is to allow user to select these apps BEFORE the OS finished launching by pressing hotkeys previously binded to the apps. For example user turns on his Mac, types SMTV and goes away, when the system finishes launching my app recovers the input and launches Safari, Mail, Tweetie and Vuze. I'm new to SO but I do my best to help others by answering their questions - I think I can expect the same in return. Check my profile and my activity and after that start screaming about malware.

This question is a follow-up to the question Is it possible to recover keyboard input that was done while Mac OS was starting up?.

Guided by Pekka's advice, I've stumbled upon an article Intercepting Keyboard Events by Christian Starkjohann that describes how he and the Objective Development team succeeded in reassigning iBook's CDROM eject key from F12 to Shift+F12. The main part is that they actually intercepted keyboard events, which is what I need. In the end Christian has written this article exactly for developers like me to use the idea of iJect as a prototype for similar functionality.

To start with, I decided to create a simple kernel extension to simply log the user's keyboard input to /var/log/kernel.log. I've started a new Generic Kernel Extension project in XCode, followed the instructions of the Hello Kernel: Creating a Kernel Extension With Xcode tutorial found in Mac Dev Center's Kernel Extension Concepts to create a Hello World project and then stuffed it with code taken from iJect sources. Here are the results:

TestKEXT.c

#include <sys/systm.h>
#include <mach/mach_types.h>


extern int HidHackLoad(void);
extern int HidHackUnload(void);


kern_return_t MacOSSCKEXT_start (kmod_info_t * ki, void * d) {
    return HidHackLoad() == 0 ? KERN_SUCCESS : KERN_FAILURE;
}


kern_return_t MacOSSCKEXT_stop (kmod_info_t * ki, void * d) {
    return HidHackUnload() == 0 ? KERN_SUCCESS : KERN_FAILURE;
}

HIDHack.h

#ifdef __cplusplus
extern "C" {
#endif

#include <mach/mach_types.h>
#include <sys/systm.h>

 extern int HidHackLoad(void);
 extern int HidHackUnload(void);

#ifdef __cplusplus
}
#endif

#include <IOKit/system.h>
#include <IOKit/assert.h>
#include <IOKit/hidsystem/IOHIDSystem.h>


class HIDHack : public IOHIDSystem {
public:
 virtual void keyboardEvent(unsigned   eventType,
          /* flags */            unsigned   flags,
          /* keyCode */          unsigned   key,
          /* charCode */         unsigned   charCode,
          /* charSet */          unsigned   charSet,
          /* originalCharCode */ unsigned   origCharCode,
          /* originalCharSet */  unsigned   origCharSet,
          /* keyboardType */     unsigned   keyboardType,
          /* repeat */           bool       repeat,
          /* atTime */           AbsoluteTime ts);

 virtual void keyboardSpecialEvent(unsigned   eventType,
           /* flags */        unsigned   flags,
           /* keyCode  */     unsigned   key,
           /* specialty */    unsigned   flavor,
           /* guid */         UInt64     guid,
           /* repeat */       bool       repeat,
           /* atTime */       AbsoluteTime ts);
};

HIDHack.cpp

#include "HIDHack.h"


static void *oldVtable = NULL;
static void *myVtable = NULL;


int HidHackLoad(void) {
 IOHIDSystem *p;
 HIDHack *sub;

 if (oldVtable != NULL) {
  printf("###0 KEXT is already loaded\n");
  return 1;
 }
 if (myVtable == NULL) {
  sub = new HIDHack();
  myVtable = *(void **)sub;
  sub->free();
 }
    p = IOHIDSystem::instance();
    oldVtable = *(void **)p;
    *(void **)p = myVtable;

 printf("###1 KEXT has been successfully loaded\n");

    return 0;
}

int HidHackUnload(void) {
 IOHIDSystem *p;

    if (oldVtable != NULL) {
        p = IOHIDSystem::instance();
  if (*(void **)p != myVtable) {
   printf("###2 KEXT is not loaded\n");

   return 1;
  }
        *(void **)p = oldVtable;
        oldVtable = NULL;
    }

 printf("###3 KEXT has been successfully unloaded\n");

 return 0;
}

void HIDHack::keyboardEvent(unsigned   eventType, unsigned   flags, unsigned   key, unsigned   charCode, unsigned   charSet, unsigned   origCharCode, unsigned   origCharSet, unsigned   keyboardType, bool repeat,
       AbsoluteTime ts) {
 printf("###4 hid event type %d flags 0x%x key %d kbdType %d\n", eventType, flags, key, keyboardType);

    IOHIDSystem::keyboardEvent(eventType, flags, key, charCode, charSet, origCharCode, origCharSet, keyboardType, repeat, ts);
}

void HIDHack::keyboardSpecialEvent(   unsigned   eventType,
          /* flags */        unsigned   flags,
          /* keyCode  */     unsigned   key,
          /* specialty */    unsigned   flavor,
          /* guid */         UInt64     guid,
          /* repeat */       bool       repeat,
          /* atTime */       AbsoluteTime ts) {
 printf("###5 special event type %d flags 0x%x key %d flavor %d\n", eventType, flags, key, flavor);

 IOHIDSystem::keyboardSpecialEvent(eventType, flags, key, flavor, guid, repeat, ts);
}

The resulting kernel extension gets successfully loaded/unloaded by kextload/kextunload programs, but doesn't actually intercept any of the keyboard events. I've tried doing lots of things to get it working, but without any errors or other problems with it in the way I can't google anything useful and ask your help.

A: 

Why should we help you write trojans? All your questions seem to be of a dubious nature.

Charles Eli Cheese
Both of his questions have only asked how to get keyboard input as soon as possible. I see no reason why such requests would warrant *that* kind of accusation.
Sukasa
how to hide form varibales in php script. How to make my HidHack kernel function log keys? Kernel as in not inside a user program. I apologize if I am wrong but this is still the kind of crap we don't need floating around the web even if his particular use is benign (which seems unlikely).
Charles Eli Cheese
Hi Sukasa and Charles Eli Cheese! In case you really want to know, I'm asking these questions to see if it's possible for me to allow my Mac OS application's users to give it commands before the OS (and, therefore, my app) is loaded. I'm 100% frank with you and, please do believe me, do not intend to harm fellow Mac users in any way.
Ivan Karpan
.....Yeah right!
TFD
Charles, you remind me of the DMCA. If we are to suppress any knowledge that can be used for evil, we're all gonna be pretty stupid.
Nicholas Knight
More like suppressing stupidity. Too bad it is so hard to do so.
Charles Eli Cheese