【原】DIY屬於自己的鼠標側鍵


現在的鼠標功能越來越強大,不單單只有左右中三鍵,有更多的按鍵,比如5鍵,7鍵,20+鍵、、、我也順便淘了一個5鍵的鼠標。但是無奈國產貨(Understand?),鼠標側面的兩個鍵完全白費了,只能用來當前進后退鍵。看到羅技、Razor的鼠標按鍵自定義爽爽的,心里就不舒服,然后萌生了這個想法——自己來重新DIY下這倆個雞肋按鍵。

網上資料倒是一大堆,先分析下這個工程怎么實現。

由於是從打開軟件開始這兩個按鍵一直要處於DIY的條件下,所以遠程注入不能實現,否則要一一注入那還不麻煩死?殺毒軟件也要來一直阻止你的。丟個例子,試試就知道有多蛋疼了:

#include <windows.h>

#include <iostream.h>

 

bool EnableDebugPriv()

{

    HANDLE hToken;

    LUID sedebugnameValue;

    TOKEN_PRIVILEGES tkp;

 

    if (!OpenProcessToken(GetCurrentProcess(),

        TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {

        return false;

    }

 

    if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &sedebugnameValue)) {

        CloseHandle(hToken);

        return false;

    }

 

    tkp.PrivilegeCount = 1;

    tkp.Privileges[0].Luid = sedebugnameValue;

    tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

 

    if (!AdjustTokenPrivileges(hToken, FALSE, &tkp, sizeof(tkp), NULL, NULL)) {

        CloseHandle(hToken);

        return false;

    }

 

    return true;

}

 

BOOL InitDll(const char *DllFullPath, const DWORD dwRemoteProcessId)

{

EnableDebugPriv();

 

HANDLE hRemoteProcess;

 

    //打開遠程線程

    hRemoteProcess = OpenProcess( PROCESS_ALL_ACCESS, FALSE, dwRemoteProcessId );

 

char *pszLibFileRemote;

 

    //使用VirtualAllocEx函數在遠程進程的內存地址空間分配DLL文件名空間

    pszLibFileRemote = (char *) VirtualAllocEx( hRemoteProcess, NULL, lstrlen(DllFullPath)+1,

MEM_COMMIT, PAGE_READWRITE);

 

    //使用WriteProcessMemory函數將DLL的路徑名寫入到遠程進程的內存空間

    WriteProcessMemory(hRemoteProcess, pszLibFileRemote, (void *) DllFullPath,

lstrlen(DllFullPath)+1, NULL);

 

DWORD dwID;

LPVOID pFunc = LoadLibraryA;

HANDLE hRemoteThread = CreateRemoteThread(hRemoteProcess, NULL, 0,

(LPTHREAD_START_ROUTINE)pFunc, pszLibFileRemote, 0, &dwID );

 

 

if(hRemoteThread == NULL)

{

cout<<"注入線程失敗!"<<endl;

return 0;

}

    CloseHandle(hRemoteProcess);

    CloseHandle(hRemoteThread);

 

    return TRUE;

}

 

int main()

{

    InitDll("E:\\工作區間\\源程序\\遠程注入\\Debug\\iGazeU.dll", 576) ;//這個dll你所要注入的dll文件,這個數字是你想注入的進程的PID

    return 0;

}

 

所以另尋方法了。

熟悉Windows的童鞋也許能通過修改注冊表實現小部分功能,比方說把按鍵映射,連編寫都省了,但是絕對做不出自定義想要的功能,比方說復制粘貼什么的。

最后,只有靠一種方法了,就是用全局鈎子。

全局鈎子?沒怎么看過的童鞋一定覺得很神秘,360有時候也會提示帶有Hook字樣的內容,其實鈎子只是一個紙老虎。

Windows和DOS最大的區別就是消息。現在學編程的童鞋肯定知道一個面向過程的程序是怎么編的,但是可能並不清楚面向對象的程序是怎么寫的,比方說一個狀態欄帶有動態時間顯示的記事本是怎么顯示的?如果用面向過程寫,記事本要輸入文字,又要定時刷新時間,兩個事情怎么可能同時做?所以說,消息就是Windows提醒程序什么時候做什么事情,程序只要循環不斷接收消息就行了。就像這樣:

while (GetMessage(&msg, NULL, 0, 0))  //程序永遠在接收消息

{

if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 

{

TranslateMessage(&msg);

DispatchMessage(&msg);

}

}

我們現在研究的核心,就是怎么讓Windows在向程序發送鼠標側鍵消息的時候把這個消息攔截掉,改掉並換成自定義的消息,這就是鈎子的本來面目。

最重要的一關被我們跨過去了,現在是實戰階段了。

打開你的VS2010,或者VC6也一樣,由於MFC比較方便,很多代碼都是自動添加好的,所以我們以MFC為例:

1、新建一個 MFC AppWizarddll) 工程,選擇 MFC擴展DLL(使用共享MFC DLL),建立工程名為TestHook

為什么要建立DLL(動態連接庫)?Windows坑爹的規定,沒辦法,人家是老大,只能聽他的,Linux沒試過,應該會好很多。

DLL是什么?普及下,就是獨立出來的庫,比方說你有n+1個程序都要使用 void max(int *a, int *b)

{

a ^= b ^= a ^= b;

}

那么你只需寫一個這樣的功能,做成DLL,你就可以讓n+1個程序都可以用它了,是不是很方便?

2、打開stdafx.h,在#include <afxwin.h>上面加入:

#define _WIN32_WINNT 0x500

stdafx.h最后面加上:

#include <windows.h>

#include <winuser.h>

這是什么意思呢?你可以打開winuser.h看看,原來_WIN32_WINNT是用來區分系統版本的,我們的程序只能在Windows 2000和以上版本的電腦才能運行。

3、打開TestHook.def,在最下面加入:

SECTIONS

mydata READ WRITE SHARED

4、現在來做幾個函數了,用類來管理比較方便,應該說是一個好習慣。先來定義一個類:新建頭文件MouseHook.h,寫上:

class AFX_EXT_CLASS CMouseHook:public CObject

{

public:

CMouseHook();

~CMouseHook();

 

BOOL startHook();

BOOL stopHook();

static LRESULT CALLBACK MouseProc(int nCode,WPARAM wParam,LPARAM lParam);

};

再新建一個MouseHook.cpp,添加以下代碼:

#include "stdafx.h"

#include "MouseHook.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#endif

 

#pragma data_seg("mydata")

HHOOK glhHook = NULL;

HINSTANCE glhInstance = NULL;

#pragma data_seg()

 

CMouseHook::CMouseHook()

{

}

 

CMouseHook::~CMouseHook()

{

stopHook();

}

LRESULT CALLBACK CMouseHook::MouseProc(int nCode,WPARAM wParam,LPARAM lParam)

{

return CallNextHookEx(glhHook, nCode, wParam, lParam);

}

BOOL CMouseHook::startHook()

{

BOOL bResult = FALSE; 

glhHook = SetWindowsHookEx(WH_MOUSE_LL, CMouseHook::MouseProc, glhInstance, 0); 

 

if(glhHook != NULL) 

bResult = TRUE; 

 

return bResult; 

}

 

BOOL CMouseHook::stopHook()

{

if (glhHook == NULL)

{

MessageBox(NULL, _T("NULL HOOK"), _T("glhHook"), MB_OK);

}

 

BOOL bResult = FALSE; 

 

bResult = UnhookWindowsHookEx(glhHook); 

if(bResult) 

MessageBox(NULL, _T("UnhookWindowsHookEx Success"), _T("glhHook"), MB_OK);

glhHook = NULL; 

}

 

return bResult;

}

5、現在是關鍵代碼了,我們的代碼都在

LRESULT CALLBACK CMouseHook::MouseProc(int nCode,WPARAM wParam,LPARAM lParam)

{

return CallNextHookEx(glhHook, nCode, wParam, lParam);

}

中完成,具體代碼如下:

LRESULT CALLBACK CMouseHook::MouseProc(int nCode,WPARAM wParam,LPARAM lParam)

{

LPMSLLHOOKSTRUCT pMouseHook = (MSLLHOOKSTRUCT*)lParam;

if (nCode >= 0)

{

If (wParam==WM_XBUTTONDOWN && HIWORD(pMouseHook->mouseData)==XBUTTON1)

{

//寫上自己代碼

return TRUE;

}

 

if (wParam == WM_XBUTTONUP && HIWORD(pMouseHook->mouseData)==XBUTTON1)

{

//寫上自己代碼

return TRUE;

}

 

if (wParam == WM_XBUTTONDOWN && HIWORD(pMouseHook->mouseData)==XBUTTON2)

{

//寫上自己代碼

return TRUE;

}

 

if (wParam == WM_XBUTTONUP && HIWORD(pMouseHook->mouseData)==XBUTTON2)

{

//寫上自己代碼

return TRUE;

}

}

return CallNextHookEx(glhHook, nCode, wParam, lParam);

}

VC6的童鞋會說了,為什么我編譯下后程序出現N多錯誤?其實是VC6太老了,有些庫比較新,沒有得到更新。只要在cpp#include "stdafx.h"下加上這些:

#define WM_XBUTTONDOWN 0x020B

#define WM_XBUTTONUP 0x020C

#define XBUTTON1 0x1

#define XBUTTON2 0x2

是不是行了呢?

 

注意:VC6要把_T()去掉,比方說_T("glhHook")變成"glhHook"。

由於5鍵鼠標不是常規鼠標,而我們使用的是低級鈎子(Low-Level Hook)因此要用MSLLHOOKSTRUCT結構體。

 

6、做完DLL當然要有程序去調用啊,接下來做一個調用程序(以VC6為例):

(1)新建一個MFC EXE工程Mouse,把做完的Dll工程下的Debug目錄下的TestHook.lib和Dll工程目錄中的MouseHook.h拷貝到新建工程的目錄下,按快捷鍵Alt+F7打開工程設置,點擊 連接 選項卡,在對象/庫模塊中填寫TestHook.lib,打開MouseDlg.h,在#include "stdafx.h"下方加入

#include "MouseHook.h",

然后在class CMouseDlg : public CDialog下的public:下加入:

CMouseHook m_hook;

切換到MouseDlg.cpp,在BOOL CMouseDlg::OnInitDialog()下的SetIcon(m_hIcon, FALSE); // Set small icon

下加入

m_hook.startHook();

然后編譯鏈接吧。

 

現在,把做完的TestHook.dll和Mouse.exe放在同一個目錄下,打開是不是發現鼠標的側鍵被屏蔽了?因為我們到現在都沒有加入自己想要的功能,又是運行了直接return TRUE; 所以截取的消息直接被吃掉了!

加個小功能吧,有些童鞋的鼠標左右鍵不好用了,可以臨時代替應急:

LRESULT CALLBACK CMouseHook::MouseProc(int nCode,WPARAM wParam,LPARAM lParam)

{

int cx=GetSystemMetrics(SM_CXSCREEN);//得到屏幕寬度

int cy=GetSystemMetrics(SM_CYSCREEN);//得到屏幕高度

LONG ldx = pMouseHook->pt.x * 65535 / cx;

LONG ldy = pMouseHook->pt.y * 65535 / cy;

 

LPMSLLHOOKSTRUCT pMouseHook = (MSLLHOOKSTRUCT*)lParam;

 

if (nCode >= 0)

{

If (wParam==WM_XBUTTONDOWN && HIWORD(pMouseHook->mouseData)==XBUTTON1)

{

INPUT input[1];

ZeroMemory(&input, sizeof(INPUT));

 

//鼠標左鍵彈起

input[0].type = INPUT_MOUSE;

input[0].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;

input[0].mi.dx = ldx;

input[0].mi.dy = ldy;

 

SendInput(

1, // count of input events

input, // array of input events

sizeof(INPUT) // size of structure

);

 

return TRUE;

}

 

if (wParam == WM_XBUTTONUP && HIWORD(pMouseHook->mouseData)==XBUTTON1)

{

INPUT input[1];

ZeroMemory(&input, sizeof(INPUT));

 

//鼠標左鍵彈起

input[0].type = INPUT_MOUSE;

input[0].mi.dwFlags = MOUSEEVENTF_LEFTUP;

input[0].mi.dx = ldx;

input[0].mi.dy = ldy;

 

SendInput(

1, // count of input events

input, // array of input events

sizeof(INPUT) // size of structure

);

 

return TRUE;

}

 

if (wParam == WM_XBUTTONDOWN && HIWORD(pMouseHook->mouseData)==XBUTTON2)

{

INPUT input[1];

ZeroMemory(&input, sizeof(INPUT));

 

//鼠標左鍵彈起

input[0].type = INPUT_MOUSE;

input[0].mi.dwFlags = MOUSEEVENTF_RIGHTDOWN;

input[0].mi.dx = ldx;

input[0].mi.dy = ldy;

 

SendInput(

1, // count of input events

input, // array of input events

sizeof(INPUT) // size of structure

);

 

return TRUE;

}

 

if (wParam == WM_XBUTTONUP && HIWORD(pMouseHook->mouseData)==XBUTTON2)

{

INPUT input[1];

ZeroMemory(&input, sizeof(INPUT));

 

//鼠標左鍵彈起

input[0].type = INPUT_MOUSE;

input[0].mi.dwFlags = MOUSEEVENTF_RIGHTUP;

input[0].mi.dx = ldx;

input[0].mi.dy = ldy;

 

SendInput(

1, // count of input events

input, // array of input events

sizeof(INPUT) // size of structure

);

 

return TRUE;

}

}

return CallNextHookEx(glhHook, nCode, wParam, lParam);

}

 

寫到了這里,就是那么多了,其實也沒多少技術含量的事情,接下來怎么玩看各位的想法了,比方說自動打怪,設置快捷鍵什么的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM