このキーボードインターセプトカーネル拡張機能が機能しないのはなぜですか?
-
19-09-2019 - |
質問
私の仲間の開発者!この質問に含まれるテキストの量に少なくともあなたの何人かがおびえていないことを非常に願っています(私は単に人道的に説明できるように最善を尽くしました)。 :)
マルウェアなどを書くためにこの質問をしたと思う人に。 OSが終了した後にユーザーが[アプリケーション]を選択できるアプリケーションを作成したいと思います。全体のアイデアは、OSが以前にアプリにバインドされていたHotkeysを押すことにより、OSが起動を終了する前に、ユーザーがこれらのアプリを選択できるようにすることです。たとえば、ユーザーは自分のMacをオンにし、SMTVをタイプして消えます。システムが終了したときにアプリが起動して入力を回復し、Safari、Mail、Tweetie、Vuzeを起動します。私はそのままですが、彼らの質問に答えることで他の人を助けるために最善を尽くします - 私は見返りに同じことを期待できると思います。私のプロフィールとアクティビティを確認し、その後マルウェアについて叫び始めます。
この質問は、質問のフォローアップです Mac OSが起動している間に行われたキーボード入力を回復することは可能ですか?.
によって導かれます ペッカのアドバイス, 、私は記事に出くわしました キーボードイベントの傍受 クリスチャン・スタークハンによって、彼とどのように説明しているかを説明しています 客観的な開発チーム iBookのCDROM EjectキーをF12からShift+F12に再割り当てすることに成功しました。主な部分は、実際に彼らがいるということです 傍受されます キーボードイベント、これが必要なものです。最終的に、クリスチャンは私のような開発者が同様の機能のプロトタイプとしてIedのアイデアを使用するために、この記事を正確に書いています。
まず、単純なカーネル拡張機能を作成して、ユーザーのキーボード入力を単純にログインすることにしました。 /var/log/kernel.log
. 。 Xcodeで新しいジェネリックカーネル拡張プロジェクトを開始しましたが、 こんにちはカーネル:Xcodeでカーネル拡張機能を作成します で見つかったチュートリアル Mac Dev Centerのカーネル拡張コンセプト 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プログラムによって正常にロード/ロードされますが、実際にはキーボードイベントをインターセプトしません。私はそれを機能させるためにたくさんのことをしようとしましたが、エラーやその他の問題はありません。
解決
問題は、既存のiohidsystemインスタンスをどのようにオーバーライドしているかではありません。それはうまく機能します。
問題は、Iohikeyboardが開かれたときに、イベントを処理するためにiohidsystemにコールバック関数に渡されることです。コールバックは、_keyboardEventと呼ばれるiohidsystemの静的なプライベート機能です。
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);
それは仮想である10パラメーター1を呼び出しません(そしてあなたがオーバーライドしている)。代わりに、呼ばれているのは11のパラメーターではないものです。したがって、11パラメーター1をオーバーライドしようとしたとしても、コールがVtableを通過しないため、機能しません。