Question

Mes collègues développeurs! J'espère bien qu'au moins certains d'entre vous n'auront pas peur par la quantité de texte que cette question contient (j'ai simplement fait de mon mieux pour être aussi descriptif que possible). :)

À ceux qui pensent avoir posé cette question d'écrire des logiciels malveillants ou quelque chose comme ça. Je souhaite écrire une application qui permettra aux utilisateurs de sélectionner le lancement des applications une fois le système d'exploitation terminé le lancement. L'idée est de permettre à l'utilisateur de sélectionner ces applications avant la fin du lancement du système d'exploitation en appuyant sur les raccourcis clavier précédemment impliqués aux applications. Par exemple, l'utilisateur allume son Mac, tape SMTV et disparaît, lorsque le système termine le lancement de mon application récupère l'entrée et lance Safari, Mail, Tweetie et Vuze. Je suis nouveau dans le domaine, mais je fais de mon mieux pour aider les autres en répondant à leurs questions - je pense que je peux m'attendre à la même chose en retour. Vérifiez mon profil et mon activité et après cela, commencez à crier sur les logiciels malveillants.

Cette question est un suivi de la question Est-il possible de récupérer l'entrée du clavier qui a été effectuée pendant le démarrage du Mac OS?.

Guidé par Les conseils de Pekka, Je suis tombé sur un article Intercepter les événements de clavier par Christian Starkjohann qui décrit comment lui et le Équipe de développement objectif a réussi à réaffecter la clé CDROM d'iBook de F12 à Shift + F12. La partie principale est qu'ils intercepté Événements de clavier, ce dont j'ai besoin. En fin de compte, Christian a écrit cet article exactement pour que des développeurs comme moi utilisent l'idée d'Iject comme prototype pour des fonctionnalités similaires.

Pour commencer, j'ai décidé de créer une simple extension de noyau pour enregistrer simplement l'entrée du clavier de l'utilisateur à /var/log/kernel.log. J'ai commencé un nouveau projet d'extension de noyau générique dans Xcode, j'ai suivi les instructions du Bonjour le noyau: Création d'une extension du noyau avec Xcode tutoriel trouvé dans Concepts d'extension du noyau de Mac Dev Center Pour créer un projet Hello World, puis le fourré avec du code tiré de sources Iject. Voici les résultats:

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);
}

L'extension du noyau résultant est chargée / déchargée avec succès par les programmes KEXTload / KextUnload, mais n'intercepte réellement aucun des événements du clavier. J'ai essayé de faire beaucoup de choses pour le faire fonctionner, mais sans aucune erreur ou d'autres problèmes de la manière dont je ne peux rien Google et demandez votre aide.

Était-ce utile?

La solution

Le problème ne concerne pas la façon dont vous remplacez l'instance IOHIDSystem existante. Cela fonctionne très bien.

Le problème est que lorsque iOhikeyboard est ouvert, il est passé une fonction de rappel à l'iohidSystem pour le traitement des événements. Le rappel est une fonction privée statique de iohidSystem, appelé _keyboardEvent:

    success = ((IOHIKeyboard*)source)->open(this, kIOServiceSeize,0,
                (KeyboardEventCallback)        _keyboardEvent, 
                (KeyboardSpecialEventCallback) _keyboardSpecialEvent,
                (UpdateEventFlagsCallback)     _updateEventFlags);

Le rappel appelle ensuite la fonction KeyboardEvent dans l'instance iohidSystem:

    self->keyboardEvent(eventType, flags, key, charCode, charSet,
                            origCharCode, origCharSet, keyboardType, repeat, ts, sender);

Il n'appelle pas le paramètre Ten One, qui est virtuel (et que vous remplacez). Au lieu de cela, ce que l'on appelle est le paramètre 11 non virtuel. Donc, même si vous essayiez de remplacer le paramètre 11, cela ne fonctionnerait pas car l'appel ne passe jamais par le VTable.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top