لماذا لا تعترض لوحة المفاتيح هذه أعمال ملحق النواة؟

StackOverflow https://stackoverflow.com/questions/2042795

سؤال

زملائي المطورين! آمل أن يكون هناك الكثير منكم على الأقل لن يخيفه مقدار النص الذي يحتوي عليه هذا السؤال (ببساطة بذل قصارى جهدي ليكون وصفيا كما كان ممكنا إنسانيا). :)

لأولئك الذين يعتقدون أنني سألت هذا السؤال كتابة البرامج الضارة أو شيء من هذا. أريد أن أكتب تطبيقا يسمح للمستخدمين بتحديد التطبيقات التي سيتم إطلاقها بعد إنهاء نظام التشغيل. تتمثل الفكرة الكاملة في السماح للمستخدم بتحديد هذه التطبيقات قبل الانتهاء من تشغيل نظام التشغيل عن طريق الضغط على مفاتيح مفاتيح مثبت مسبقا على التطبيقات. على سبيل المثال، يقوم المستخدم بتشغيل MAC، وأنواع SMTV ويطفو بعيدا، عندما ينتهي نظام التشغيل لإطلاق تطبيقي يستعيد الإدخال وإطلاق Safari، البريد، Tweetie و Vuze. أنا جديد، لكنني أبذل قصارى جهدي لمساعدة الآخرين عن طريق الإجابة على أسئلتهم - أعتقد أنني يمكن أن أتوقع نفس الشيء في المقابل. تحقق ملف التعريف الخاص بي ونشاطي وبعد أن تبدأ الصراخ حول البرامج الضارة.

هذا السؤال هو متابعة للسؤال هل من الممكن استعادة إدخال لوحة المفاتيح التي تم ذلك أثناء بدء تشغيل Mac OS؟.

مسترشد ب نصيحة بيكا, ، لقد تعثرت على مقال اعتراض أحداث لوحة المفاتيح من قبل كريستيان ستاركوهان الذي يصف كيف هو و فريق تطوير موضوعي نجح في إعادة تعيين مفتاح الإلكتروم الإلكتروني في iBook من F12 لتحويل + F12. الجزء الرئيسي هو أنهم في الواقع اعترضت أحداث لوحة المفاتيح، وهذا ما أحتاج إليه. في النهاية، كتب المسيحية هذه المقالة بالضبط للمطورين مثلي لاستخدام فكرة الإذار كأحد النموذج الأولي لوظائف مماثلة.

لتبدأ، قررت إنشاء ملحق Kernel بسيط لإدخال إدخال لوحة مفاتيح المستخدم ببساطة /var/log/kernel.log. وبعد لقد بدأت مشروع امتداد Kernel عام جديد في Xcode، اتبع تعليمات مرحبا kernel: إنشاء ملحق النواة مع xcode البرنامج التعليمي الموجود في مفاهيم نواة ملحق مركز ماك ديف لإنشاء مشروع World Hello ثم محشوته برمز مأخوذ من مصادر الإذار. فيما يلي النتائج:

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

يحصل تحميل / إلغاء تحميل / إلغاء تحميل Kernel الناتج عن برامج التحميل KNXTLOAD / KEXTUNLOAD، ولكنه لا يعترض فعليا على اعتراض أي من أحداث لوحة المفاتيح. لقد حاولت القيام بالكثير من الأشياء للحصول عليها في العمل، ولكن دون أي أخطاء أو مشاكل أخرى معها في الطريقة التي لا أستطيع فيها جوجل أي شيء مفيد واسأل مساعدتكم.

هل كانت مفيدة؟

المحلول

المشكلة ليست مع كيفية تجاوز مثيل IOhidSystem الموجود. التي تعمل على ما يرام.

المشكلة هي أنه عند فتح ioheikeyboard، يتم تمرير وظيفة رد اتصال إلى نظام Iohidsystem لمعالجة الأحداث. رد الاتصال هي وظيفة خاصة ثابتة في Iohidsystem، تسمى _KEYBoardEvent:

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

ثم يستدعي رد الاتصال بوظيفة KeyboardEvent في مثيل IOHIDSYSTEM:

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

لا يطلق على المعلمة العشرة الأولى، وهو افتراضي (والتي تتجاوزها). بدلا من ذلك، ما يسمى هو 11 المعلمة غير الظاهري واحد. لذا، حتى لو حاولت تجاوز المعلمة 11، فلن تعمل كإجراء مكالمة أبدا عبر VTable.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top