Home

Published

- 4 min read

IOCTLs on Windows vs Linux

img of IOCTLs on Windows vs Linux

IOCTL: Windows vs Linux

IOCTLs (Input/Output Control) are crucial in both Windows and Linux for performing device-specific operations beyond what’s available through standard system drivers. Despite serving similar functions, their implementation and usage vary significantly between the two operating systems.

1. Concept & Usage

  • Windows: Primarily used in kernel-mode drivers to communicate with and to control hardware devices
  • Linux: Commonly used in both kernel modules and user-space applications for device interactions

2. Background 6 Implementation

FeatureWindowsLinux
InterfaceDeviceIoControl functionioctl system call
Header Fileswinioctl.h, ntddk.hlinux/ioctl.h, asm/ioctl.h
Definition MethodCTL_CODE macro_IO, _IOW, _IOR, _IOWR macros
SecurityManaged via security descriptorsControlled by file permissions and capability checks
Usage ContextKernel-mode drivers and user-mode applicationsPrimarily user-space applications, also used in kernel modules
Common UsesDevice management (e.g., ejecting USB devices), custom driver commandsDevice configuration, special file operations, custom driver commands
Permission HandlingRequires administrative privileges for direct device accessRoot access or appropriate permissions needed for device files
Error HandlingGetLastError() to retrieve detailed error informationReturn codes and errno for error identification
Data TransferInput/Output buffers specified in callData passed directly through ioctl parameters or via pointers to data structures
DocumentationMSDN documentation and driver development kitsLinux man pages and kernel documentation

3. Practical Coding Example

Finding Device Number on Windows

For USB devices, we can use Get-Disk in PowerShell to list all disks and find the correct device number.

powershell
   $ Get-Disk

Ejecting a USB Device with IOCTLs

Here’s how we can invoke an IOCTL to eject a USB device using a hybrid PowerShell/C# approach.

Demo

IOCTL USB Eject

Source

powershell
   $code = @'
using System;
using System.Runtime.InteropServices;

public class IOCTLInvoker {
    [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Winapi)]
    public static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

    [DllImport("kernel32.dll", SetLastError = true)]
    public static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, IntPtr lpInBuffer, uint nInBufferSize, IntPtr lpOutBuffer, uint nOutBufferSize, out uint lpBytesReturned, IntPtr lpOverlapped);

    public const uint GENERIC_READ = 0x80000000;
    public const uint GENERIC_WRITE = 0x40000000;
    public const uint OPEN_EXISTING = 3;

    public static bool SendIOCTL(string devicePath, uint ioctlCode) {
        IntPtr device = CreateFile(devicePath, GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
        if (device.ToInt64() == -1) {
            Console.WriteLine("Failed to open device. Error: " + Marshal.GetLastWin32Error());
            return false;
        }

        uint bytesReturned;
        bool result = DeviceIoControl(device, ioctlCode, IntPtr.Zero, 0, IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);
        if (!result) {
            Console.WriteLine("DeviceIoControl failed. Error: " + Marshal.GetLastWin32Error());
        }
        return result;
    }
}
'@

Add-Type -TypeDefinition $code -Language CSharp

$devicePath = "\\.\PhysicalDriveN"  # Replace N with the actual device number
$ioctlCode = 0x002D4808  # IOCTL code for ejecting media

if ([IOCTLInvoker]::SendIOCTL($devicePath, $ioctlCode)) {
    "USB device ejected successfully."
} else {
    "Failed to eject USB device."
}

IOCTL on Linux

Like Named Pipes, IOCTL exist on Linux and Windows, but work quite differently. We added two simple IOCTL Linux examples to provide some foundational knowledge.

Blinking Keyboard LEDs using IOCTL

For a concise and direct demonstration of IOCTL in Linux, we do another simple example: using IOCTL to blink a keyboard LEDs on and off. This is a demonstration of IOCTL’s capability to interact with devices at a low level.

C Example

This C program turn Caps Lock on and off (depending on the keyboard, it may blink). It requires root permissions to run.

c
   #include <stdio.h>
#include <stdlib.h>
#include <linux/kd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>

int main() {
    int console_fd = open("/dev/console", O_NOCTTY);

    if(console_fd == -1) {
        perror("Cannot open /dev/console");
        return EXIT_FAILURE;
    }

    // Blink the Caps Lock LED
    for(int i = 0; i < 5; i++) {
        ioctl(console_fd, KDSETLED, LED_CAP);
        sleep(1);
        ioctl(console_fd, KDSETLED, 0);
        sleep(1);
    }

    close(console_fd);
    return EXIT_SUCCESS;
}
bash
   $ gcc -o blink_led blink_led.c
$ sudo ./blink_led`

Python Example

Using the fcntl module in Python to perform a similar operation.

python
   import fcntl
import os
import time

# Constants for the ioctl commands
KDSETLED = 0x4B32
LED_CAP = 0x04

# Open the console device
console_fd = os.open('/dev/console', os.O_NOCTTY)

# Blink the Caps Lock LED
for i in range(5):
    fcntl.ioctl(console_fd, KDSETLED, LED_CAP)
    time.sleep(1)
    fcntl.ioctl(console_fd, KDSETLED, 0)
    time.sleep(1)

os.close(console_fd)

Notes

  • Permissions: Both examples require root access due to the direct hardware manipulation.
  • Device Path: This uses /dev/console for simplicity, but actual device paths may vary.
  • Practical Use: While these examples demonstrate basic IOCTL usage in Linux, real-world applications often involve more complex operations and error handling.

Outlook

We’ve been demonstrating the ejection of a USB device on Windows, to show the practical application of IOCTLs in managing hardware directly from scripts and applications.

We made this small exercise as preparation to understand an evasion method using LOL Drivers as process killers, which we’ll look at in an upcoming article.

https://www.loldrivers.io/
https://alice.climent-pommeret.red/posts/process-killer-driver/
https://github.com/h0mbre/ioctl.py
https://github.com/xalicex/Killers/