2010-01-11 12 views
5

mis compañeros desarrolladores! Espero mucho que al menos algunos de ustedes no se asusten por la cantidad de texto que contiene esta pregunta (simplemente hice todo lo posible por ser tan descriptivo como humanamente posible). :)¿Por qué este teclado que intercepta la extensión del núcleo no funciona?

Para aquellos que piensan que he hecho esta pregunta para escribir malware o algo así. Quiero escribir una aplicación que permita a los usuarios seleccionar las aplicaciones que se lanzarán después de que el SO termine de ejecutarse. La idea general es permitir que el usuario seleccione estas aplicaciones ANTES de que el sistema operativo termine de iniciarse presionando las teclas rápidas enlazadas previamente a las aplicaciones. Por ejemplo, el usuario enciende su Mac, escribe SMTV y se va, cuando el sistema termina de ejecutar mi aplicación recupera la entrada y ejecuta Safari, Mail, Tweetie y Vuze. Soy nuevo en SO, pero hago todo lo posible para ayudar a los demás respondiendo sus preguntas. Creo que puedo esperar lo mismo a cambio. Verifique mi perfil y mi actividad, y luego empiece a gritar sobre el malware.

Esta pregunta es una continuación de la pregunta Is it possible to recover keyboard input that was done while Mac OS was starting up?.

Guiados por Pekka's advice, me he tropezado con un artículo Intercepting Keyboard Events por Christian Starkjohann que describe cómo él y el Objective Development team tuvo éxito en la reasignación de tecla de expulsión de CD-ROM del iBook de F12 para Shift + F12. La parte principal es que en realidad interceptaron los eventos del teclado, que es lo que necesito. Al final, Christian ha escrito este artículo exactamente para que desarrolladores como yo usen la idea de iJect como prototipo de funcionalidad similar.

Para empezar, decidí crear una extensión de kernel simple para simplemente registrar la entrada del teclado del usuario en /var/log/kernel.log. Comencé un nuevo proyecto de Extensión de Kernel genérico en XCode, seguí las instrucciones del tutorial Hello Kernel: Creating a Kernel Extension With Xcode que se encuentra en Mac Dev Center's Kernel Extension Concepts para crear un proyecto de Hello World y luego rellenarlo con el código tomado de las fuentes de iJect. Aquí están los resultados:

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

T La extensión kernel resultante se carga/descarga con éxito mediante los programas kextload/kextunload, pero en realidad no intercepta ninguno de los eventos del teclado. He intentado hacer muchas cosas para que funcione, pero sin errores u otros problemas en el modo en que no puedo buscar nada útil en google y pedir tu ayuda.

+0

¡Hola Svante! Muchas gracias por ayudarme con la gramática. No soy un hablante nativo, aunque estoy haciendo todo lo posible para no irritar demasiado a la gente ...;) –

+1

Por lo que puedo ver, los gritos de malware no tienen fundamento (aunque alguien que busque escribir malware podría hacer preguntas similares). Cualquier programa en este profundo * nivel * podría ser * malware, por eso es el trabajo del sistema operativo preguntar al usuario antes de instalarlo. Por supuesto, Ivan, * sería * posible interceptar las pulsaciones de teclado de un diálogo de contraseña de esa manera, no lo había pensado yo mismo, que podría ser la razón por la que no funciona. Tal vez el sistema operativo es lo suficientemente inteligente como para evitar la interceptación exactamente por esa razón. –

+0

Tal vez tengas razón ... Aunque hasta donde he entendido todo el truco está basado en la capacidad del lenguaje C++ para sustituir las tablas de direcciones de las clases por métodos, lo que debería funcionar en cualquier caso. –

Respuesta

2

El problema no está en cómo se anula la instancia de IOHIDSystem existente. Eso funciona bien.

El problema es que cuando se abre el IOHIKeyboard, se pasa una función de devolución de llamada al sistema IOHIDS para el procesamiento de eventos.La devolución de llamada es una función privada estática de IOHIDSystem, llamado _keyboardEvent:

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

la devolución de llamada a continuación, llama a la función KeyboardEvent en la instancia IOHIDSystem:

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

No llaman los diez parámetro de uno, lo que es virtual (y que está anulando). En cambio, lo que se llama es el parámetro 11 no virtual. Por lo tanto, incluso si tratara de anular el parámetro 11, no funcionaría, ya que la llamada nunca pasa por el vtable.

Cuestiones relacionadas