zoukankan      html  css  js  c++  java
  • [转] 驱动模拟键盘鼠标

    标 题: 【原创】我写的模拟挂
    作 者: asrn
    时 间: 2013-05-07,23:32:09
    链 接: http://bbs.pediy.com/showthread.php?t=171203
    
    发出来,一为抛砖引玉,论坛应该也有很多xd想写外挂,可以参考下;二来想出去找份工作,本人年近30岁,而且还没有编码的工作经验,没有信心,希望大家能给点意见。。
    驱动最初参考了http://bbs.pediy.com/showthread.php?t=101653
    中的代码,因为是根据特征码搜索,不爽,后面又根据寒江独钓中的代码作了修改(这里要澄清下,不是为寒江独钓打广告,反而我觉得那书写得不清不楚的)。
    
    原理:通过直接调用Kbdclass的回调函数KeyboardClassServiceCallback直接给上层发送键盘驱动,就可以实现模拟键盘操作,鼠标类似。
    通过windbg查看类设备下面的端口设备(i8042prt)或usb设备(kbdhid),其设备对象中的DeviceExtension里面保存了设备对象与KeyboardClassServiceCallback回调函数,设备对象保存在回调函数前面一个地址中。
    
    
    这个是驱动扩展结构,用来保存查找到的设备对象和回调函数,避免直接使用全局变量
    typedef struct _DEVICE_EXTENSION {
    
        PDEVICE_OBJECT       kbdDeviceObject;        //键盘类设备对象
        PDEVICE_OBJECT       mouDeviceObject;        //鼠标类设备对象
        MY_KEYBOARDCALLBACK  My_KbdCallback;         //KeyboardClassServiceCallback函数 
        MY_MOUSECALLBACK     My_MouCallback;         //MouseClassServiceCallback函数
    
    }DEVICE_EXTENSION, *PDEVICE_EXTENSION;
    
    下面是查找KeyboardClassServiceCallback的关键函数,鼠标设备查找方法类似,我合成了一个函数
    NTSTATUS GetKmclassInfo(PDEVICE_OBJECT DeviceObject, USHORT Index)
    {
        NTSTATUS           status;
        UNICODE_STRING     ObjectName;
        PCWSTR             kmhidName, kmclassName, kmName;
        PVOID              kmDriverStart;
        ULONG              kmDriverSize;
        PVOID*             TargetDeviceObject;
        PVOID*             TargetclassCallback;
        PDEVICE_EXTENSION  deviceExtension;
        PDRIVER_OBJECT     kmDriverObject       = NULL;
        PDRIVER_OBJECT     kmclassDriverObject  = NULL;
    
    
        deviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
    
        switch(Index)
        {
        case KEYBOARD_DEVICE:
            kmName              = L"kbd";
            kmhidName           = L"\\Driver\\kbdhid";
            kmclassName         = L"\\Driver\\kbdclass";
            TargetDeviceObject  = (PVOID*)&(deviceExtension->kbdDeviceObject);
            TargetclassCallback = (PVOID*)&(deviceExtension->My_KbdCallback);
            break;
        case MOUSE_DEVICE:
            kmName              = L"mou";
            kmhidName           = L"\\Driver\\mouhid";
            kmclassName         = L"\\Driver\\mouclass";
            TargetDeviceObject  = (PVOID*)&(deviceExtension->mouDeviceObject);
            TargetclassCallback = (PVOID*)&(deviceExtension->My_MouCallback);
            break;
        default:
            return STATUS_INVALID_PARAMETER;
        }
    
    
        // 通过USB类设备获取驱动对象
        RtlInitUnicodeString(&ObjectName, kmhidName);
        status = ObReferenceObjectByName(&ObjectName,
            OBJ_CASE_INSENSITIVE,
            NULL,
            FILE_READ_ACCESS,
            *IoDriverObjectType,
            KernelMode,
            NULL,
            (PVOID*)&kmDriverObject);
    
    
        if(!NT_SUCCESS(status))
        {
            // 通过i8042prt获取驱动对象
            RtlInitUnicodeString(&ObjectName, L"\\Driver\\i8042prt");
            status = ObReferenceObjectByName(&ObjectName,
                OBJ_CASE_INSENSITIVE,
                NULL, 
                FILE_READ_ACCESS,
                *IoDriverObjectType,
                KernelMode,
                NULL,
                (PVOID*)&kmDriverObject);
            if(!NT_SUCCESS(status))
            {
                KdPrint(("Couldn't Get the i8042prt Driver Object\n"));
                return status;
            }
        }
    
        // 通过kmclass获取键盘鼠标类驱动对象
        RtlInitUnicodeString(&ObjectName, kmclassName);
        status = ObReferenceObjectByName(&ObjectName,
            OBJ_CASE_INSENSITIVE,
            NULL,
            FILE_READ_ACCESS,
            *IoDriverObjectType,
            KernelMode,
            NULL,
            (PVOID*)&kmclassDriverObject);
    
        if(!NT_SUCCESS(status))
        {
            KdPrint(("Couldn't Get the kmclass Driver Object\n"));
            return status;
        }
        else
        {
            kmDriverStart = kmclassDriverObject->DriverStart;
            kmDriverSize  = kmclassDriverObject->DriverSize;
        }
     
        ULONG             DeviceExtensionSize;
        PULONG            kmDeviceExtension;
        PDEVICE_OBJECT    kmTempDeviceObject;
        PDEVICE_OBJECT    kmclassDeviceObject;
        PDEVICE_OBJECT    kmDeviceObject = kmDriverObject->DeviceObject;
        while (kmDeviceObject)
        {
            kmTempDeviceObject = kmDeviceObject;
            while (kmTempDeviceObject)
            {
                kmDeviceExtension   = (PULONG)kmTempDeviceObject->DeviceExtension;
                kmclassDeviceObject = kmclassDriverObject->DeviceObject;
                DeviceExtensionSize = ((ULONG)kmTempDeviceObject->DeviceObjectExtension - (ULONG)kmTempDeviceObject->DeviceExtension) / 4;
                while (kmclassDeviceObject)
                {
                    for (ULONG i = 0; i < DeviceExtensionSize; i++)
                    {
                        if (kmDeviceExtension[i] == (ULONG)kmclassDeviceObject &&
                            kmDeviceExtension[i + 1] > (ULONG)kmDriverStart    &&
                            kmDeviceExtension[i + 1] < (ULONG)kmDriverStart + kmDriverSize)
                        {
                            // 将获取到的设备对象保存到自定义扩展设备结构
                            *TargetDeviceObject  = (PVOID)kmDeviceExtension[i];
                            *TargetclassCallback = (PVOID)kmDeviceExtension[i + 1];
                            KdPrint(("%SDeviceObject == 0x%x\n", kmName, kmDeviceExtension[i]));
                            KdPrint(("%SClassServiceCallback == 0x%x\n", kmName, kmDeviceExtension[i + 1]));
                            return STATUS_SUCCESS;
                        }
                    }
                    kmclassDeviceObject = kmclassDeviceObject->NextDevice;
                }
                kmTempDeviceObject = kmTempDeviceObject->AttachedDevice;
            }
            kmDeviceObject = kmDeviceObject->NextDevice;
        }
        return STATUS_UNSUCCESSFUL;
    }
    
    应用层模拟键盘操作函数
    BOOL KeyboardButton(USHORT VirtualKey, USHORT Flags)
    {
        KEYBOARD_INPUT_DATA  kid ;
        DWORD dwOutput;
    
        HANDLE hDevice = CreateFile(KEYMOUSE_WIN32_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
            0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hDevice == INVALID_HANDLE_VALUE)
            return FALSE;
    
        memset(&kid, 0, sizeof(KEYBOARD_INPUT_DATA));
    
        kid.Flags    = Flags;
        kid.MakeCode = (USHORT)MapVirtualKey(VirtualKey, 0);
    
        BOOL bRet = DeviceIoControl(hDevice, IOCTL_KEYBOARD, &kid, sizeof(KEYBOARD_INPUT_DATA), NULL, 0, &dwOutput, NULL);
    
        if (!bRet)
            TRACE(_T("Error! please open the simulate kmclass driver!\n"));
        CloseHandle(hDevice);
    
        return bRet;
    }
    
    模拟鼠标的函数
    BOOL MouseMove(LONG dx, LONG dy, USHORT Flags)
    {
        MOUSE_INPUT_DATA  mid ;
        DWORD dwOutput;
    
        HANDLE hDevice = CreateFile(KEYMOUSE_WIN32_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
            0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hDevice == INVALID_HANDLE_VALUE)
            return FALSE;
    
        memset(&mid, 0, sizeof(MOUSE_INPUT_DATA));
    
        mid.Flags = Flags;
        switch (mid.Flags)
        {
        case MOUSE_MOVE_RELATIVE:
            mid.LastX = dx;
            mid.LastY = dy;
            break;
        case MOUSE_MOVE_ABSOLUTE:
            mid.LastX = dx * 0xffff / GetSystemMetrics(SM_CXSCREEN);
            mid.LastY = dy * 0xffff / GetSystemMetrics(SM_CYSCREEN);
            break;
        default:
            TRACE(_T("Flags: Parameter error!\n"));
            return FALSE;
        }
    
        BOOL bRet = DeviceIoControl(hDevice, IOCTL_MOUSE, &mid, sizeof(MOUSE_INPUT_DATA), NULL, 0, &dwOutput, NULL);
    
        if (!bRet)
            TRACE(_T("Error! please start the kmclass driver!\n"));
        CloseHandle(hDevice);
    
        return bRet;
    }
    
    
    另外一个是前台窗口找图的实现
    bmp类定义
    class Cbm {
    private:
      BITMAPFILEHEADER   bmfh;                 // 位图文件头
      BITMAPINFOHEADER   bmih;                 // 位图信息头
      PBYTE              pBits;                // 位图像素位指针
      int                cBits;                // 位图每行所用字节总数
      int                cxDib;                // 位图水平像素宽度
      int                cyDib;                // 位图垂直像素高度
    
      void SetcBits() {cBits = ((cxDib * bmih.biBitCount + 31) & ~31) >> 3;}
      void SetcxDib() {cxDib = bmih.biWidth;}
      void SetcyDib() {cyDib = bmih.biHeight;}
    ....
    }
    
    // 通过窗口图像获取位图信息
    Cbm::Cbm(HWND hwndScreen)
    {
        HDC     hdc, hdcMem, hdcScreen;
        HBITMAP hBitmap;
        RECT    rect;
    
        if (!hwndScreen)
        {
            memset(&rect, 0, sizeof(RECT));
            rect.right   = GetSystemMetrics(SM_CXSCREEN);
            rect.bottom  = GetSystemMetrics(SM_CYSCREEN);
        }else
            GetClientRect(hwndScreen, &rect);    //获得截图窗口的范围大小
    
        hdc     = GetDC(NULL);
        hdcMem  = CreateCompatibleDC(hdc);
        hBitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left, rect.bottom - rect.top);
        SelectObject(hdcMem, hBitmap);
    
        hdcScreen  = GetDC(hwndScreen);
        BitBlt(hdcMem, 0, 0, rect.right - rect.left, rect.bottom - rect.top, hdcScreen, 0, 0, SRCCOPY);
    
        DeleteDC(hdcMem);
        ReleaseDC(hwndScreen, hdcScreen);
    
        //初始化信息头bmi结构
        memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
        bmih.biSize        = sizeof(BITMAPINFOHEADER);
        bmih.biWidth       = rect.right - rect.left;
        bmih.biHeight      = rect.bottom - rect.top;
        bmih.biBitCount    = 24;
        bmih.biCompression = BI_RGB;
        bmih.biPlanes      = 1;
    
        SetcxDib();
        SetcyDib();
        SetcBits();
    
        //获取pBits的值
        pBits = new BYTE [cBits * cyDib];
    
        GetDIBits(hdc, hBitmap, 0, cyDib, pBits, (LPBITMAPINFO)&bmih, DIB_RGB_COLORS);
    
        //初始化文件头bmfh
        bmfh.bfType      = 0x4D42;
        bmfh.bfSize      = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + cBits * cyDib;
        bmfh.bfReserved1 = 0;
        bmfh.bfReserved2 = 0;
        bmfh.bfOffBits   = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
    
        ReleaseDC(NULL, hdc);
        DeleteObject(hBitmap);
    }
    
    
    // 通过加载文件获取位图信息
    Cbm::Cbm(PCTSTR FilePath)
    {
        HANDLE hFile = CreateFile(FilePath, GENERIC_READ, 
            FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            pBits = NULL;
            TRACE(_T("read file failed. FileName: %s\n"), FilePath);
            return;
        }
    
        DWORD dwBytesRead;
        if ( !(ReadFile(hFile, &bmfh, sizeof(BITMAPFILEHEADER), &dwBytesRead, NULL) &&
            ReadFile(hFile, &bmih, sizeof(BITMAPINFOHEADER), &dwBytesRead, NULL) &&
            bmfh.bfType == 0x4D42) )
        {
            pBits = NULL;
            TRACE(_T("read file failed. FileName: %s\n"), FilePath);
            CloseHandle(hFile);
            return;
        }
    
        SetcxDib();
        SetcyDib();
        SetcBits();
    
        pBits = new BYTE [cBits * cyDib];
        if (!ReadFile(hFile, pBits, cBits * cyDib, &dwBytesRead, NULL))
        {
            delete [] pBits;
            pBits = NULL;
            TRACE(_T("read file failed. FileName: %s\n"), FilePath);
        }
        CloseHandle(hFile);
    }
    
    // 保存位图到文件
    BOOL Cbm::SaveBitmapToFile(PCTSTR FileName, LPCRECT pRect) const
    {
        ASSERT(pBits);
    
        TCHAR FilePath[MAX_PATH], DefaultFileName[MAX_PATH];
        //创建以系统时间命名的bmp文件
        SYSTEMTIME time;
        GetLocalTime(&time);
        wsprintf(DefaultFileName, _T("%04u%02u%02u%02u%02u%02u%03u.bmp"),
            time.wYear, time.wMonth, time.wDay, time.wHour, time.wMinute, time.wSecond, time.wMilliseconds);
    
        //修正保存路径,默认保存至当前程序目录Screen文件夹
        if (!FileName)
            wsprintf(FilePath, _T("%s\\%s"), _T("screen"), DefaultFileName);
        else
        {
            if (FileName[1] == ':')
                _tcscpy_s(FilePath, FileName);
            else
                wsprintf(FilePath, _T("%s\\%s"), _T("screen"), FileName);
    
    
            if (FileName[lstrlen(FileName) - 1] == '\\' || FileName[lstrlen(FileName) - 1] == '/')
                _tcscat_s(FilePath, MAX_PATH, DefaultFileName);
        }
    
        // 判断文件路径是否有效,无效则创建路径中没有的文件夹
        if (!PathIsDirectory(FilePath))
            CreateFolder(FilePath);
    
        //保存数据
        HANDLE hFile = CreateFile(FilePath, GENERIC_WRITE, 0 ,NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile == INVALID_HANDLE_VALUE)
            return FALSE;
    
    
        DWORD dwBytesWritten;
        Cbm bmFile(*this, pRect);
        BOOL bSuccess = WriteFile(hFile, &bmFile.bmfh, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL) &&
                        WriteFile(hFile, &bmFile.bmih, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL) &&
                        WriteFile(hFile, bmFile.pBits, bmFile.cBits * bmFile.cyDib, &dwBytesWritten, NULL);
    
        CloseHandle(hFile);
        if (!bSuccess)
            DeleteFile(FilePath);
    
        return bSuccess;
    }
    
    
    找图函数
    BOOL FindPic(const Cbm & bmWnd, const Cbm & bmFile, LPCRECT rectTarget, OUT PRECT retRect, int resemble, COLORREF rgb)
    {
        if (!(bmFile.pBits && bmWnd.pBits) || bmFile.cxDib > bmWnd.cxDib || bmFile.cyDib > bmWnd.cyDib)
            return FALSE;
    
        resemble = max(resemble, 0);
        resemble = min(resemble, 100);
    
        BYTE r = GetRValue(rgb);
        BYTE g = GetGValue(rgb);
        BYTE b = GetBValue(rgb);
    
    
        // 实际范围
        RECT rectDefault;
        if (rectTarget && bmWnd.IsInRect(*rectTarget))
            rectDefault = *rectTarget;
        else
            bmWnd.GetBitmapRect(rectDefault);
    
        // bmFile图像坐标(x, y),  bmWnd图像坐标(x + xOffset, y + yOffset)
        int yTotal        =    rectDefault.bottom - bmFile.cyDib;
        int xTotal        =    rectDefault.right - bmFile.cxDib;
        int invalidTotal  =    (100 - resemble) * (bmFile.cxDib * bmFile.cyDib);
        int validTotal    =    resemble * (bmFile.cxDib * bmFile.cyDib);
    
    
        //  ignoreNum忽略值, validNum有效值,invalidNum无效值
        int invalidNum = 0, validNum = 0,  ignoreNum = 0;
        for (int yOffset = rectDefault.top; yOffset <= yTotal; yOffset++)
            for (int xOffset = rectDefault.left; xOffset <= xTotal; xOffset++)
            {
                for (int y = 0, bflag = TRUE; bflag && (y < bmFile.cyDib); y++)
                    for (int x = 0; x < bmFile.cxDib; x++)
                    {
                        int FileIndex = (bmFile.cyDib - 1 - y) * bmFile.cBits + 3 * x;
                        int WndIndex  = (bmWnd.cyDib - 1 - yOffset - y) * bmWnd.cBits + 3 * (xOffset + x);
    
    
                        if (r    == bmFile.pBits[FileIndex + 2] &&
                            g    == bmFile.pBits[FileIndex + 1] &&
                            b    == bmFile.pBits[FileIndex]     &&
                            0xF8 != bmWnd.pBits[WndIndex + 2]   &&
                            0xFC != bmWnd.pBits[WndIndex + 1]   &&
                            0xF8 != bmWnd.pBits[WndIndex]) {
    
                                ignoreNum++;
                        }    
                        else if (bmFile.pBits[FileIndex + 2] == bmWnd.pBits[WndIndex + 2] &&
                            bmFile.pBits[FileIndex + 1] == bmWnd.pBits[WndIndex + 1] &&
                            bmFile.pBits[FileIndex] == bmWnd.pBits[WndIndex]) {
    
                                validNum++;
                        }
                        else
                            invalidNum++;
    
    
                        if (100 * invalidNum > invalidTotal)
                        {
                            invalidNum = validNum = ignoreNum = 0;
                            bflag = FALSE;
                            break;
                        }
    
                        if (100 * (validNum + ignoreNum) >= validTotal)
                        {
                            if (retRect)
                            {
                                retRect->left   = xOffset;
                                retRect->top    = yOffset;
                                retRect->right  = xOffset + bmFile.cxDib;
                                retRect->bottom = yOffset + bmFile.cyDib;
                            }
                            return TRUE;
                        }
                    }
            }
            return FALSE;
    }
    
    多图查找函数
    BOOL FindSomePic(const Cbm & bmWnd, PCTSTR FileName, LPCRECT rectTarget, PRECT retRect, PTSTR retFileName, int resemble, COLORREF rgb)
    {
        WIN32_FIND_DATA fData;
        BOOL  bFind = FALSE;
        TCHAR FilePath[MAX_PATH];
        TCHAR FileDir[MAX_PATH];
        _tcscpy_s(FilePath, MAX_PATH, FileName);
        _tcscpy_s(FileDir, MAX_PATH, FileName);
    
    
        if (FileName[lstrlen(FileName) - 1] == '\\')
            _tcscat_s(FilePath, MAX_PATH, _T("*.bmp"));
        else if (_tcschr(FileName, '*'))
            _tcsrchr(FileDir, '\\')[1] = '\0';
        else
        {
            bFind = FindPic(bmWnd, FileName, rectTarget, retRect, resemble, rgb);
            if (retFileName)
            {
                if (bFind)
                    _tcscpy_s(retFileName, MAX_PATH, FileName);
                else
                    retFileName[0] = '\0';
            }
    
            return bFind;
        }
    
        HANDLE hFile = FindFirstFile(FilePath, &fData);
        if (hFile == INVALID_HANDLE_VALUE)
        {
            TRACE(_T("FindSomePic --- read file failed.\n"));
            return FALSE;
        }
    
        do{
            wsprintf(FilePath, _T("%s%s"), FileDir, fData.cFileName);
            bFind = FindPic(bmWnd, FilePath, rectTarget, retRect, resemble, rgb);
        }while (!bFind && FindNextFile(hFile, &fData));
    
        FindClose(hFile);
    
        if (retFileName)
        {
            if (bFind)
                _tcscpy_s(retFileName, MAX_PATH, fData.cFileName);
            else
                retFileName[0] = '\0';
        }
    
        return bFind;
    }
    
    忘记说了,模拟鼠标移动需要关闭 控制面板->鼠标->指针选项->提高指针精确度  这个选项
    整个项目是VS2008创建,驱动工程是通过visualddk的向导添加的。
    驱动在XP、win7下测试通过
    附件有完整项目的代码 

    http://bbs.pediy.com/showthread.php?t=171203

  • 相关阅读:
    2018-5-19-创建不带BOM-的UTF8
    2018-5-19-创建不带BOM-的UTF8
    2019-2-27-win10-uwp-去掉-Flyout-边框
    2019-2-27-win10-uwp-去掉-Flyout-边框
    PHP addChild() 函数
    PHP addAttribute() 函数
    PHP __construct() 函数
    PDOStatement::setFetchMode
    PDOStatement::setAttribute
    自动收集执行计划
  • 原文地址:https://www.cnblogs.com/moher/p/3082512.html
Copyright © 2011-2022 走看看