2010-01-11 68 views
5

我的开发人员!我非常希望至少你们中的一些人不会因为这个问题包含的文本的数量而感到害怕(我尽我所能尽可能描述人性化)。 :)这个键盘为什么不拦截内核扩展工作?

对于那些以为我问过这个问题写恶意软件或东西。我想编写一个应用程序,允许用户在操作系统启动后选择要启动的应用程序。整个想法是允许用户在操作系统完成启动之前通过按下以前绑定到应用程序的热键来选择这些应用程序。例如,用户打开他的Mac,键入SMTV并消失,当系统启动我的应用程序恢复输入并启动Safari,Mail,Tweetie和Vuze时。我是新来的,但我尽我所能通过回答他们的问题来帮助别人 - 我想我可以期待同样的回报。检查我的个人资料和我的活动,然后开始尖叫有关恶意软件。

此问题是对Is it possible to recover keyboard input that was done while Mac OS was starting up?问题的后续处理。

通过Pekka's advice的指导下,我在基督教Starkjohann文章Intercepting Keyboard Events描述他和Objective Development team如何成功地从F12重新分配的iBook的光驱弹出键为Shift + F12跌跌撞撞。主要部分是他们实际上截获键盘事件,这是我需要的。最后,Christian为我这样的开发人员准备了这篇文章,将iJect的想法作为类似功能的原型。

首先,我决定创建一个简单的内核扩展,以简单地将用户的键盘输入记录到/var/log/kernel.log。我已经在XCode中启动了一个新的Generic Kernel Extension项目,按照Mac Dev Center's Kernel Extension Concepts中的Hello Kernel: Creating a Kernel Extension With Xcode教程中的说明创建Hello World项目,然后用从iJect源代码获取的代码填充它。下面是结果:

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

ŧ他产生的内核扩展通过kextload/kextunload程序成功加载/卸载,但实际上并没有拦截任何键盘事件。我试着做很多事情来让它工作,但没有任何错误或其他问题,我无法谷歌任何有用的方式,并要求你的帮助。

+0

Hey Svante!非常感谢您帮助我学习语法。虽然我尽我所能不要激怒人们太多......) – 2010-01-11 21:45:58

+1

从我所看到的情况来看,恶意软件的哭声是毫无根据的(即使有人正在编写恶意软件也会提出类似的问题)。在这个深层次上的任何程序*都可能是恶意软件,这就是为什么操作系统的任务是在用户安装之前询问用户。当然,伊凡,它可能会以这种方式拦截密码对话框的击键 - 没有想到我自己 - 这可能是它不起作用的原因。也许操作系统足够聪明,以防止因为这个原因被拦截。 – 2010-01-23 20:35:46

+0

也许你是对的......尽管据我了解,整个技巧都是基于C++语言的能力,以将地址类表替换为方法,这在任何情况下都可以工作。 – 2010-01-23 21:21:41

回答

2

问题不在于如何重写现有的IOHIDSystem实例。这工作得很好。

问题是,当IOHIKeyboard打开时,它会将一个回调函数传递给IOHIDSystem以处理事件。回调是IOHIDSystem的静态私有函数,称为_keyboardEvent:

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

然后回调在IOHIDSystem实例调用的KeyboardEvent功能:

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

它不叫十个参数之一,它是虚拟的(和你重写)。相反,被称为11参数的非虚拟参数。所以即使你试图覆盖11参数,它也不会工作,因为调用永远不会通过vtable。