Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement ctypes-based Text Injection for Secure Paste Shortcut on Windows #27

Open
drankush opened this issue Feb 3, 2025 · 0 comments
Assignees
Labels
enhancement New feature or request text-injection

Comments

@drankush
Copy link
Owner

drankush commented Feb 3, 2025

Currently, the secure_paste_report() function decrypts and injects text into the active window using platform-specific methods. While the macOS implementation uses AppleScript to inject text directly into applications, the Windows implementation is incomplete. To address this, I propose implementing a ctypes-based solution for injecting text into editor windows on Windows, bypassing the clipboard.

Proposed Solution

The ctypes library allows us to interact with the Windows API at a low level. Using the PostMessageW function, we can send raw input messages (WM_CHAR, WM_KEYDOWN, WM_KEYUP) to simulate typing directly into the active window. Here’s an example implementation:

import ctypes
import time

# Define necessary constants
WM_CHAR = 0x0102
WM_KEYDOWN = 0x0100
WM_KEYUP = 0x0101
VK_RETURN = 0x0D

def inject_text_windows(text):
    """Injects text directly into the active window on Windows using ctypes."""
    user32 = ctypes.windll.user32
    
    # Get the handle of the active window
    hwnd = user32.GetForegroundWindow()
    
    # Send each character in the text
    for line in text.splitlines():
        for char in line:
            vk_code = ord(char)  # Virtual key code for the character
            user32.PostMessageW(hwnd, WM_CHAR, vk_code, 0)  # Send character
            time.sleep(0.01)  # Small delay to simulate human typing
        
        # Send Enter key after each line
        user32.PostMessageW(hwnd, WM_KEYDOWN, VK_RETURN, 0)  # Enter key down
        time.sleep(0.01)
        user32.PostMessageW(hwnd, WM_KEYUP, VK_RETURN, 0)  # Enter key up
How It Works
  1. Retrieve Active Window Handle: The GetForegroundWindow function retrieves the handle of the currently active window.
  2. Simulate Key Presses: The PostMessageW function sends WM_CHAR messages for each character in the decrypted text and simulates the Enter key (VK_RETURN) after each line.
  3. Bypass Clipboard: This approach avoids using the clipboard entirely, ensuring secure injection of sensitive data.
Current Limitations

While this solution works reliably in some applications (e.g., Chrome), it behaves inconsistently in others:

  • Microsoft Word: Text injection may fail or behave unpredictably.
  • Notepad: Inconsistent behavior observed, especially when the application is not fully focused.

This inconsistency likely arises because some applications (e.g., Word) use advanced input handling mechanisms that do not rely solely on WM_CHAR messages.

Future Work

To address these limitations, we should explore using the SendInput API for low-level keyboard simulation. Unlike PostMessageW, SendInput simulates hardware-level input events, which are more universally recognized by applications. A potential implementation could look like this:

import ctypes
from ctypes import wintypes

# Define necessary structures and constants
INPUT_KEYBOARD = 1
KEYEVENTF_KEYDOWN = 0x0000
KEYEVENTF_KEYUP = 0x0002

class KEYBDINPUT(ctypes.Structure):
    _fields_ = [
        ("wVk", wintypes.WORD),
        ("wScan", wintypes.WORD),
        ("dwFlags", wintypes.DWORD),
        ("time", wintypes.DWORD),
        ("dwExtraInfo", ctypes.c_ulonglong),
    ]

class INPUT(ctypes.Structure):
    _fields_ = [("type", wintypes.DWORD), ("ki", KEYBDINPUT)]

def simulate_key_press(vk_code):
    """Simulates a key press using SendInput."""
    input_event = INPUT(type=INPUT_KEYBOARD, ki=KEYBDINPUT(wVk=vk_code))
    ctypes.windll.user32.SendInput(1, ctypes.byref(input_event), ctypes.sizeof(input_event))

def simulate_key_release(vk_code):
    """Simulates a key release using SendInput."""
    input_event = INPUT(type=INPUT_KEYBOARD, ki=KEYBDINPUT(wVk=vk_code, dwFlags=KEYEVENTF_KEYUP))
    ctypes.windll.user32.SendInput(1, ctypes.byref(input_event), ctypes.sizeof(input_event))

def inject_text_with_sendinput(text):
    """Injects text using SendInput for low-level keyboard simulation."""
    for char in text:
        vk_code = ord(char.upper()) if char.isalpha() else ord(char)
        simulate_key_press(vk_code)
        simulate_key_release(vk_code)

This approach would provide more consistent behavior across applications, including Microsoft Word and Notepad.

Next Steps
  1. Test Current Implementation: Validate the ctypes solution in various applications to identify edge cases.
  2. Explore SendInput: Implement and test the SendInput API for broader compatibility.
  3. Document Behavior: Clearly document which applications are supported and any known limitations.
References
@drankush drankush added enhancement New feature or request text-injection labels Feb 3, 2025
@drankush drankush self-assigned this Feb 3, 2025
drankush added a commit that referenced this issue Feb 3, 2025
Implementing c-types based text injection #27
@drankush drankush closed this as completed Feb 8, 2025
@drankush drankush reopened this Feb 8, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request text-injection
Projects
None yet
Development

No branches or pull requests

1 participant