NtUserInjectKeyboardInput函数绕过杀软屏幕锁定模拟键鼠
字数 1620 2025-08-22 22:47:30

Windows内部API:NtUserInjectKeyboardInput函数详解与实战应用

1. 函数概述

NtUserInjectKeyboardInput是Windows操作系统内部的未公开API,属于NtUser系列函数之一。该函数主要用于模拟键盘输入,具有以下关键特性:

  • 未公开性:微软未在标准SDK中提供官方文档
  • 低层次调用:属于系统底层调用,直接与输入子系统交互
  • 高优先级:在所有键盘模拟函数中具有最高优先级(约等于虚拟键盘级别)
  • 应用场景:常见于需要绕过安全软件屏幕锁定的场景(如游戏外挂)

2. 函数原型与参数解析

2.1 函数原型

NTSTATUS NtUserInjectKeyboardInput(
    ULONG dwFlags,          // 注入标志
    PKEYBDINPUT pKeyBdInput, // 键盘输入结构指针
    ULONG cInputs           // 输入事件数量
);

2.2 参数详解

  1. dwFlags

    • 指定注入的标志
    • 通常设置为0,表示正常的键盘输入
    • 其他可能的标志值未公开
  2. pKeyBdInput

    • 指向KEYBDINPUT结构的指针
    • 描述具体的键盘事件(按键、状态等)
  3. cInputs

    • 指定要注入的键盘事件数量
    • 通常为1(单个按键事件)

3. KEYBDINPUT结构体

typedef struct tagKEYBDINPUT {
    USHORT wVk;         // 虚拟键码
    USHORT wScan;       // 扫描码
    DWORD dwFlags;      // 事件标志
    DWORD time;         // 时间戳(通常为0)
    ULONG_PTR dwExtraInfo; // 附加信息(通常为0)
} KEYBDINPUT;

3.1 dwFlags标志位

标志 描述
KEYEVENTF_KEYDOWN 0x0000 按键按下事件
KEYEVENTF_KEYUP 0x0002 按键释放事件
KEYEVENTF_SCANCODE 0x0008 使用扫描码而非虚拟键码

4. 虚拟键码表

键名 键码(十六进制)
A-Z 0x41-0x5A
0-9 0x30-0x39
F1-F12 0x70-0x7B
Enter 0x0D
Esc 0x1B
Spacebar 0x20
Tab 0x09
Backspace 0x08
Ctrl 0x11
Alt 0x12
Shift 0x10
方向键 0x25-0x28

5. 键盘模拟实战代码

5.1 基础键盘模拟示例

#include <Windows.h>
#include <iostream>

int main() {
    // 创建KEYBDINPUT结构
    KEYBDINPUT ki = {0};
    ki.wVk = 0x41; // A键的虚拟键码
    ki.dwFlags = KEYEVENTF_KEYDOWN; // 按下键
    ki.wScan = MapVirtualKey(0x41, MAPVK_VK_TO_SCAN); // 获取扫描码
    
    // 设定INPUT结构
    INPUT input = {0};
    input.type = INPUT_KEYBOARD;
    input.ki = ki;
    
    // 调用NtUserInjectKeyboardInput进行键盘输入注入
    ULONG cInputs = 1;
    NtUserInjectKeyboardInput(0, &input.ki, cInputs);
    
    // 模拟释放A键
    ki.dwFlags = KEYEVENTF_KEYUP; // 释放键
    NtUserInjectKeyboardInput(0, &input.ki, cInputs);
    
    std::cout << "键盘输入注入完成" << std::endl;
    return 0;
}

5.2 组合键模拟(Ctrl+C)

#include <Windows.h>

void SimulateCtrlC() {
    // 按下Ctrl键
    KEYBDINPUT ctrlDown = {0};
    ctrlDown.wVk = VK_CONTROL;
    ctrlDown.dwFlags = KEYEVENTF_KEYDOWN;
    INPUT ctrlDownInput = {0};
    ctrlDownInput.type = INPUT_KEYBOARD;
    ctrlDownInput.ki = ctrlDown;
    
    // 按下C键
    KEYBDINPUT cDown = {0};
    cDown.wVk = 'C';
    cDown.dwFlags = KEYEVENTF_KEYDOWN;
    INPUT cDownInput = {0};
    cDownInput.type = INPUT_KEYBOARD;
    cDownInput.ki = cDown;
    
    // 释放C键
    KEYBDINPUT cUp = cDown;
    cUp.dwFlags = KEYEVENTF_KEYUP;
    INPUT cUpInput = cDownInput;
    cUpInput.ki = cUp;
    
    // 释放Ctrl键
    KEYBDINPUT ctrlUp = ctrlDown;
    ctrlUp.dwFlags = KEYEVENTF_KEYUP;
    INPUT ctrlUpInput = ctrlDownInput;
    ctrlUpInput.ki = ctrlUp;
    
    // 执行注入
    NtUserInjectKeyboardInput(0, &ctrlDownInput.ki, 1);
    NtUserInjectKeyboardInput(0, &cDownInput.ki, 1);
    NtUserInjectKeyboardInput(0, &cUpInput.ki, 1);
    NtUserInjectKeyboardInput(0, &ctrlUpInput.ki, 1);
}

6. 鼠标模拟的替代方案

虽然NtUserInjectKeyboardInput不能直接模拟鼠标,但可以通过以下方法实现高优先级的鼠标模拟:

  1. 使用SendInput移动鼠标
  2. 使用NtUserInjectKeyboardInput模拟Enter键点击(替代鼠标左键)

6.1 鼠标模拟示例代码

#include <windows.h>
#include <iostream>
#include <thread>
#include <cstdlib>
#include <ctime>

// 模拟延时
void delay(int milliseconds) {
    std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
}

// 模拟鼠标点击
void clickAt(int x, int y) {
    INPUT input = {0};
    input.type = INPUT_MOUSE;
    input.mi.dx = x;
    input.mi.dy = y;
    input.mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
    SendInput(1, &input, sizeof(INPUT)); // 移动鼠标
    delay(10);
    
    // 鼠标左键按下
    input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    SendInput(1, &input, sizeof(INPUT));
    delay(10);
    
    // 鼠标左键抬起
    input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
    SendInput(1, &input, sizeof(INPUT));
}

// 获取屏幕键盘上的"Enter"键坐标
POINT getScreenKeyboardEnterKeyPosition() {
    POINT enterKeyPosition = {50000, 20000}; // 示例位置,需根据实际情况调整
    return enterKeyPosition;
}

int main() {
    std::srand(static_cast<unsigned int>(std::time(nullptr)));
    
    // 打开目标程序
    system("start xx\\uninst.exe");
    delay(1000);
    
    // 获取窗口位置
    POINT windowCenter;
    HWND hwnd = FindWindow(NULL, TEXT("xxxx")); // 替换为实际窗口标题
    if(!hwnd) {
        std::cerr << "cant find" << std::endl;
        return -1;
    }
    
    RECT rect;
    GetWindowRect(hwnd, &rect);
    windowCenter.x = (rect.left + rect.right) / 2;
    windowCenter.y = (rect.top + rect.bottom) / 2;
    
    // 模拟鼠标移动到窗口中心
    SetCursorPos(windowCenter.x, windowCenter.y);
    delay(10);
    
    // 移动操作
    SetCursorPos(windowCenter.x - 50, windowCenter.y + 50);
    delay(10);
    
    // 打开屏幕键盘
    system("start osk.exe");
    delay(200);
    
    // 获取屏幕键盘上的"Enter"键坐标
    POINT enterKeyPosition = getScreenKeyboardEnterKeyPosition();
    
    // 模拟点击操作
    for(int i = 0; i < 5; i++) {
        // 随机偏移
        int randomOffset = std::rand() % 5;
        int direction = (std::rand() % 2 == 0) ? -1 : 1;
        
        // 更新鼠标位置
        SetCursorPos(windowCenter.x - 50 + randomOffset * direction, 
                    windowCenter.y + 50);
        
        // 模拟鼠标点击
        INPUT input = {0};
        input.type = INPUT_MOUSE;
        input.mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
        SendInput(1, &input, sizeof(INPUT));
        delay(50);
        
        input.mi.dwFlags = MOUSEEVENTF_LEFTUP;
        SendInput(1, &input, sizeof(INPUT));
        delay(50);
        
        // 模拟点击屏幕键盘上的Enter键
        clickAt(enterKeyPosition.x, enterKeyPosition.y);
    }
    
    std::cout << "操作完成!" << std::endl;
    return 0;
}

7. 高级应用技巧

7.1 绕过安全软件检测

由于NtUserInjectKeyboardInput具有高优先级,可以绕过某些安全软件的屏幕锁定机制。使用时需注意:

  1. 调用方式:通常需要通过动态获取函数地址的方式调用
  2. 注入时机:选择在安全软件检测间隙进行操作
  3. 行为模拟:配合正常的用户操作模式,避免被检测为异常行为

7.2 动态获取函数地址

#include <windows.h>

typedef NTSTATUS (WINAPI *NtUserInjectKeyboardInput_t)(ULONG, PKEYBDINPUT, ULONG);

NtUserInjectKeyboardInput_t GetNtUserInjectKeyboardInput() {
    HMODULE hUser32 = LoadLibrary("user32.dll");
    if(!hUser32) return NULL;
    
    return (NtUserInjectKeyboardInput_t)GetProcAddress(hUser32, "NtUserInjectKeyboardInput");
}

int main() {
    NtUserInjectKeyboardInput_t pNtUserInjectKeyboardInput = GetNtUserInjectKeyboardInput();
    if(!pNtUserInjectKeyboardInput) {
        printf("Failed to get function address\n");
        return -1;
    }
    
    // 使用获取的函数指针进行调用
    KEYBDINPUT ki = {0};
    ki.wVk = 'A';
    ki.dwFlags = KEYEVENTF_KEYDOWN;
    
    pNtUserInjectKeyboardInput(0, &ki, 1);
    
    return 0;
}

8. 注意事项与风险提示

  1. 法律风险:该技术可能被用于开发外挂等非法用途,请确保仅用于合法场景
  2. 系统兼容性:作为未公开API,不同Windows版本可能有所变化
  3. 稳定性风险:直接调用底层API可能导致系统不稳定
  4. 安全软件检测:现代安全软件可能会检测此类调用行为
  5. 替代方案:在合法场景下,优先考虑使用公开API如SendInputkeybd_event

9. 总结

NtUserInjectKeyboardInput作为Windows内部API,提供了高优先级的键盘输入模拟能力。通过本文的详细解析和示例代码,开发者可以:

  1. 理解该函数的工作原理和调用方式
  2. 实现高优先级的键盘输入模拟
  3. 通过替代方案实现鼠标模拟
  4. 了解相关风险和法律限制

在实际应用中,建议仅在必要情况下使用此技术,并始终遵守相关法律法规。

Windows内部API:NtUserInjectKeyboardInput函数详解与实战应用 1. 函数概述 NtUserInjectKeyboardInput 是Windows操作系统内部的未公开API,属于 NtUser 系列函数之一。该函数主要用于模拟键盘输入,具有以下关键特性: 未公开性 :微软未在标准SDK中提供官方文档 低层次调用 :属于系统底层调用,直接与输入子系统交互 高优先级 :在所有键盘模拟函数中具有最高优先级(约等于虚拟键盘级别) 应用场景 :常见于需要绕过安全软件屏幕锁定的场景(如游戏外挂) 2. 函数原型与参数解析 2.1 函数原型 2.2 参数详解 dwFlags 指定注入的标志 通常设置为0,表示正常的键盘输入 其他可能的标志值未公开 pKeyBdInput 指向 KEYBDINPUT 结构的指针 描述具体的键盘事件(按键、状态等) cInputs 指定要注入的键盘事件数量 通常为1(单个按键事件) 3. KEYBDINPUT结构体 3.1 dwFlags标志位 | 标志 | 值 | 描述 | |------|----|------| | KEYEVENTF_ KEYDOWN | 0x0000 | 按键按下事件 | | KEYEVENTF_ KEYUP | 0x0002 | 按键释放事件 | | KEYEVENTF_ SCANCODE | 0x0008 | 使用扫描码而非虚拟键码 | 4. 虚拟键码表 | 键名 | 键码(十六进制) | |------|----------------| | A-Z | 0x41-0x5A | | 0-9 | 0x30-0x39 | | F1-F12 | 0x70-0x7B | | Enter | 0x0D | | Esc | 0x1B | | Spacebar | 0x20 | | Tab | 0x09 | | Backspace | 0x08 | | Ctrl | 0x11 | | Alt | 0x12 | | Shift | 0x10 | | 方向键 | 0x25-0x28 | 5. 键盘模拟实战代码 5.1 基础键盘模拟示例 5.2 组合键模拟(Ctrl+C) 6. 鼠标模拟的替代方案 虽然 NtUserInjectKeyboardInput 不能直接模拟鼠标,但可以通过以下方法实现高优先级的鼠标模拟: 使用 SendInput 移动鼠标 使用 NtUserInjectKeyboardInput 模拟Enter键点击(替代鼠标左键) 6.1 鼠标模拟示例代码 7. 高级应用技巧 7.1 绕过安全软件检测 由于 NtUserInjectKeyboardInput 具有高优先级,可以绕过某些安全软件的屏幕锁定机制。使用时需注意: 调用方式 :通常需要通过动态获取函数地址的方式调用 注入时机 :选择在安全软件检测间隙进行操作 行为模拟 :配合正常的用户操作模式,避免被检测为异常行为 7.2 动态获取函数地址 8. 注意事项与风险提示 法律风险 :该技术可能被用于开发外挂等非法用途,请确保仅用于合法场景 系统兼容性 :作为未公开API,不同Windows版本可能有所变化 稳定性风险 :直接调用底层API可能导致系统不稳定 安全软件检测 :现代安全软件可能会检测此类调用行为 替代方案 :在合法场景下,优先考虑使用公开API如 SendInput 或 keybd_event 9. 总结 NtUserInjectKeyboardInput 作为Windows内部API,提供了高优先级的键盘输入模拟能力。通过本文的详细解析和示例代码,开发者可以: 理解该函数的工作原理和调用方式 实现高优先级的键盘输入模拟 通过替代方案实现鼠标模拟 了解相关风险和法律限制 在实际应用中,建议仅在必要情况下使用此技术,并始终遵守相关法律法规。