2010-01-11 43 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。