'遊戲外掛之進程鉤子'

Windows BigDataKer 2019-07-25
"

遊戲外掛,首先要做的就是將我們的代碼放到遊戲進程中去,以此來達到“不可告人的目的”。這裡我就介紹一種比較常用的方法。就是進程鉤子的方式將DLL放到遊戲進程中去。其實這也是一些木馬盜取賬號和密碼的方式。我們這裡只是講解通過一個進程鉤子實現代碼注入遊戲進程。由第二節我們知道怎麼去寫一個C++MFC的DLL。這裡我們首先新建一個DLL。首先和大家說下這裡我會用到4個Window AP函數。

HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName ); 

這個API是找到一個給定類名或者窗口名稱的窗口句柄。參數就不用介紹了,顧名思義,第一個參數就是窗口類名稱,第二個參數就是窗口名稱。我們在這裡只是用第二個參數。第一個參數放NULL。窗口名稱我們可以通過Spy++去獲取這是VS的一個工具:

"

遊戲外掛,首先要做的就是將我們的代碼放到遊戲進程中去,以此來達到“不可告人的目的”。這裡我就介紹一種比較常用的方法。就是進程鉤子的方式將DLL放到遊戲進程中去。其實這也是一些木馬盜取賬號和密碼的方式。我們這裡只是講解通過一個進程鉤子實現代碼注入遊戲進程。由第二節我們知道怎麼去寫一個C++MFC的DLL。這裡我們首先新建一個DLL。首先和大家說下這裡我會用到4個Window AP函數。

HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName ); 

這個API是找到一個給定類名或者窗口名稱的窗口句柄。參數就不用介紹了,顧名思義,第一個參數就是窗口類名稱,第二個參數就是窗口名稱。我們在這裡只是用第二個參數。第一個參數放NULL。窗口名稱我們可以通過Spy++去獲取這是VS的一個工具:

遊戲外掛之進程鉤子

打開這個工具。

"

遊戲外掛,首先要做的就是將我們的代碼放到遊戲進程中去,以此來達到“不可告人的目的”。這裡我就介紹一種比較常用的方法。就是進程鉤子的方式將DLL放到遊戲進程中去。其實這也是一些木馬盜取賬號和密碼的方式。我們這裡只是講解通過一個進程鉤子實現代碼注入遊戲進程。由第二節我們知道怎麼去寫一個C++MFC的DLL。這裡我們首先新建一個DLL。首先和大家說下這裡我會用到4個Window AP函數。

HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName ); 

這個API是找到一個給定類名或者窗口名稱的窗口句柄。參數就不用介紹了,顧名思義,第一個參數就是窗口類名稱,第二個參數就是窗口名稱。我們在這裡只是用第二個參數。第一個參數放NULL。窗口名稱我們可以通過Spy++去獲取這是VS的一個工具:

遊戲外掛之進程鉤子

打開這個工具。

遊戲外掛之進程鉤子

將那個圓拖到遊戲標題欄後鬆開我們就可以看到這個遊戲窗口的標題了。我們根據這個標題去找窗口句柄。

DWORD GetWindowThreadProcessId( HWND hWnd, LPDWORD lpdwProcessId );

這個API返回創建指定窗口的線程ID,MSDN上這樣說的 “This function retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window”

參數hWnd是窗口句柄。就是FindWindow函數返回的值。lpdwProcessId是創建窗口的進程標誌ID,它是一個輸出參數,也就是一個指針。就和C#中的out參數差不多。這個參數可以放NULL,如果不是NULL,它會返回創建指定窗口的進程標誌。

HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn,HINSTANCE hMod, DWORD dwThreadId);

這個API就是設置鉤子。第一個參數是鉤子類型。鉤子類型具體有哪些可以參照MSDN這裡我們用到的是WH_KEYBOARD。第二個參數就是一個回調函數。回調函數的格式如下:

LRESULT CALLBACK KeyboardProc( int code,
WPARAM wParam,
LPARAM lParam
);

第三個參數就是DLL的模塊句柄,我們可以通過API函數來獲取

HMODULE GetModuleHandle( LPCTSTR lpModuleName);

這個時候大家就會疑惑了SetWindowsHookEx的第三個參數是HINSTANCE類型,但是GetModuleHandle返回的卻是HMODULE,這個能對上嗎?其實能對上。你可以看看定義它的頭文件,我們能看到typedef HINSTANCE HMODULE 這樣大家就很容易看出它們其實就是一個東西。這在Windows 核心編程中經常碰到這種情況。我們在寫Windows遊戲外掛的時候,最好要去研究下Windows 核心編程。推薦一本比較耐看的書《windows核心編程》,我的是最新版.這本書的作者絕對Windows系統有很高的研究。值得反覆去看,去研究。不跑題了,繼續……。GetModuleHandle的第一個參數就是要注入的DLL路徑可以是相當也可以絕對,當然我推薦相對路徑。SetWindowsHookEx的最後一個參數就是GetWindowThreadProcessId返回的值。通過這樣的講解大家應該瞭解了。

下面就是實實在在的編碼。我們新建一個MFC DLL(我這個DLL的名稱是GameHookDLL)。

///鉤子回調函數
LRESULT CALLBACK KeyboardProc( int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
){
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if(wParam==VK_F1&&((lParam&(1<<31))==0)){
AfxMessageBox(L"F1鍵在遊戲窗口被按下了!");
}
return CallNextHookEx(0,code,wParam,lParam);
}
//(LPWSTR)"YB_OnlineClient"
void SetHook(LPWSTR prc_name){
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HWND hd=FindWindow(NULL,prc_name);
if(hd==NULL)
{
AfxMessageBox(L"請打開輸入的程序進程");
return;
}
DWORD dwid=GetWindowThreadProcessId(hd,NULL);
//
HINSTANCE hdll=::GetModuleHandleW(L"GameHookDLL.dll");

SetWindowsHookEx(WH_KEYBOARD,&KeyboardProc,hdll,dwid);
}

這是我在DLL中添加的兩個函數,上面是SetWindowsHookEx的回調處理函數。對了,這個回調函數一定別忘了最後一行

return CallNextHookEx(0,code,wParam,lParam);如果回調KeyboardProc 中的code值小於0它會跳過去然後call下一個消息MSDN中的原文是:If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx。所以我建議還是自己研究MSDN,比較我個人能力有限,說不定理解的有誤,當然在這裡如果有什不正確或者理解有偏差的地方希望大家諒解。這裡我們DLL只需要對外暴露第二個函數void SetHook(LPWSTR prc_name)。至於怎麼暴露,自己去看第二節。

if(wParam==VK_F1&&((lParam&(1<<31))==0)){
AfxMessageBox(L"F1鍵在遊戲窗口被按下了!");
}
wParam==VK_F1表示我們按下的F1鍵。(lParam&(1<<31))==0對lParam參數不熟悉的就不好理解了。lParam的第31位如果是0表示按下,如果是1表示按鍵彈起。我們這裡是判斷F1按鍵被按下。
如果沒有(lParam&(1<<31))==0我們按下F1鍵將會彈出兩次,一次是按下時彈出,一次是F1彈起式彈出。所以要保證lParam的第31位是0我們才彈出對話框。1<<31是10000000000000000000
0000000000後面有31個0而lParam的0~30位我們不確定但是我們&一下肯定都是0,然後第31位是0最後結果肯定是0這樣就實現了判斷。

MSDN中遠英文是:

lParam[in] Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag. For more information about the lParam parameter, see Keystroke Message Flags. This parameter can be one or more of the following values.

0-15.Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key.

16-23.Specifies the scan code. The value depends on the OEM.

24.Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0.

25-28.Reserved.

29.Specifies the context code. The value is 1 if the ALT key is down; otherwise, it is 0.

30.Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.

31.Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.

接下來我們去新建一個MFC exe程序。在這個程序中去調用這個void SetHook(LPWSTR prc_name)函數。把窗口名稱作為參數傳過去。這裡我添加的是MFC 簡單對話框。對話框的佈局如圖:

"

遊戲外掛,首先要做的就是將我們的代碼放到遊戲進程中去,以此來達到“不可告人的目的”。這裡我就介紹一種比較常用的方法。就是進程鉤子的方式將DLL放到遊戲進程中去。其實這也是一些木馬盜取賬號和密碼的方式。我們這裡只是講解通過一個進程鉤子實現代碼注入遊戲進程。由第二節我們知道怎麼去寫一個C++MFC的DLL。這裡我們首先新建一個DLL。首先和大家說下這裡我會用到4個Window AP函數。

HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName ); 

這個API是找到一個給定類名或者窗口名稱的窗口句柄。參數就不用介紹了,顧名思義,第一個參數就是窗口類名稱,第二個參數就是窗口名稱。我們在這裡只是用第二個參數。第一個參數放NULL。窗口名稱我們可以通過Spy++去獲取這是VS的一個工具:

遊戲外掛之進程鉤子

打開這個工具。

遊戲外掛之進程鉤子

將那個圓拖到遊戲標題欄後鬆開我們就可以看到這個遊戲窗口的標題了。我們根據這個標題去找窗口句柄。

DWORD GetWindowThreadProcessId( HWND hWnd, LPDWORD lpdwProcessId );

這個API返回創建指定窗口的線程ID,MSDN上這樣說的 “This function retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window”

參數hWnd是窗口句柄。就是FindWindow函數返回的值。lpdwProcessId是創建窗口的進程標誌ID,它是一個輸出參數,也就是一個指針。就和C#中的out參數差不多。這個參數可以放NULL,如果不是NULL,它會返回創建指定窗口的進程標誌。

HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn,HINSTANCE hMod, DWORD dwThreadId);

這個API就是設置鉤子。第一個參數是鉤子類型。鉤子類型具體有哪些可以參照MSDN這裡我們用到的是WH_KEYBOARD。第二個參數就是一個回調函數。回調函數的格式如下:

LRESULT CALLBACK KeyboardProc( int code,
WPARAM wParam,
LPARAM lParam
);

第三個參數就是DLL的模塊句柄,我們可以通過API函數來獲取

HMODULE GetModuleHandle( LPCTSTR lpModuleName);

這個時候大家就會疑惑了SetWindowsHookEx的第三個參數是HINSTANCE類型,但是GetModuleHandle返回的卻是HMODULE,這個能對上嗎?其實能對上。你可以看看定義它的頭文件,我們能看到typedef HINSTANCE HMODULE 這樣大家就很容易看出它們其實就是一個東西。這在Windows 核心編程中經常碰到這種情況。我們在寫Windows遊戲外掛的時候,最好要去研究下Windows 核心編程。推薦一本比較耐看的書《windows核心編程》,我的是最新版.這本書的作者絕對Windows系統有很高的研究。值得反覆去看,去研究。不跑題了,繼續……。GetModuleHandle的第一個參數就是要注入的DLL路徑可以是相當也可以絕對,當然我推薦相對路徑。SetWindowsHookEx的最後一個參數就是GetWindowThreadProcessId返回的值。通過這樣的講解大家應該瞭解了。

下面就是實實在在的編碼。我們新建一個MFC DLL(我這個DLL的名稱是GameHookDLL)。

///鉤子回調函數
LRESULT CALLBACK KeyboardProc( int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
){
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if(wParam==VK_F1&&((lParam&(1<<31))==0)){
AfxMessageBox(L"F1鍵在遊戲窗口被按下了!");
}
return CallNextHookEx(0,code,wParam,lParam);
}
//(LPWSTR)"YB_OnlineClient"
void SetHook(LPWSTR prc_name){
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HWND hd=FindWindow(NULL,prc_name);
if(hd==NULL)
{
AfxMessageBox(L"請打開輸入的程序進程");
return;
}
DWORD dwid=GetWindowThreadProcessId(hd,NULL);
//
HINSTANCE hdll=::GetModuleHandleW(L"GameHookDLL.dll");

SetWindowsHookEx(WH_KEYBOARD,&KeyboardProc,hdll,dwid);
}

這是我在DLL中添加的兩個函數,上面是SetWindowsHookEx的回調處理函數。對了,這個回調函數一定別忘了最後一行

return CallNextHookEx(0,code,wParam,lParam);如果回調KeyboardProc 中的code值小於0它會跳過去然後call下一個消息MSDN中的原文是:If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx。所以我建議還是自己研究MSDN,比較我個人能力有限,說不定理解的有誤,當然在這裡如果有什不正確或者理解有偏差的地方希望大家諒解。這裡我們DLL只需要對外暴露第二個函數void SetHook(LPWSTR prc_name)。至於怎麼暴露,自己去看第二節。

if(wParam==VK_F1&&((lParam&(1<<31))==0)){
AfxMessageBox(L"F1鍵在遊戲窗口被按下了!");
}
wParam==VK_F1表示我們按下的F1鍵。(lParam&(1<<31))==0對lParam參數不熟悉的就不好理解了。lParam的第31位如果是0表示按下,如果是1表示按鍵彈起。我們這裡是判斷F1按鍵被按下。
如果沒有(lParam&(1<<31))==0我們按下F1鍵將會彈出兩次,一次是按下時彈出,一次是F1彈起式彈出。所以要保證lParam的第31位是0我們才彈出對話框。1<<31是10000000000000000000
0000000000後面有31個0而lParam的0~30位我們不確定但是我們&一下肯定都是0,然後第31位是0最後結果肯定是0這樣就實現了判斷。

MSDN中遠英文是:

lParam[in] Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag. For more information about the lParam parameter, see Keystroke Message Flags. This parameter can be one or more of the following values.

0-15.Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key.

16-23.Specifies the scan code. The value depends on the OEM.

24.Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0.

25-28.Reserved.

29.Specifies the context code. The value is 1 if the ALT key is down; otherwise, it is 0.

30.Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.

31.Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.

接下來我們去新建一個MFC exe程序。在這個程序中去調用這個void SetHook(LPWSTR prc_name)函數。把窗口名稱作為參數傳過去。這裡我添加的是MFC 簡單對話框。對話框的佈局如圖:

遊戲外掛之進程鉤子

然後給文本框關聯上CString類型的變量txt_prc_name。在按鈕事件中添加註冊鉤子代碼:

void CGameWGClientDlg::OnBnClickedOk()
{
UpdateData(true);
LPWSTR s1=(LPWSTR)(LPCTSTR)txt_prc_name;
SetHook(s1);
// TODO: 在此添加控件通知處理程序代碼
//CDialogEx::OnOK();
}

這些只需要你掌握一點MFC知識。LPWSTR s1=(LPWSTR)(LPCTSTR)txt_prc_name;這個經過兩次裝換,主要是CString類型沒法直接裝換成LPWSTR類型。所以就這樣處理了。好代碼搞定,來看效果:

"

遊戲外掛,首先要做的就是將我們的代碼放到遊戲進程中去,以此來達到“不可告人的目的”。這裡我就介紹一種比較常用的方法。就是進程鉤子的方式將DLL放到遊戲進程中去。其實這也是一些木馬盜取賬號和密碼的方式。我們這裡只是講解通過一個進程鉤子實現代碼注入遊戲進程。由第二節我們知道怎麼去寫一個C++MFC的DLL。這裡我們首先新建一個DLL。首先和大家說下這裡我會用到4個Window AP函數。

HWND FindWindow( LPCTSTR lpClassName, LPCTSTR lpWindowName ); 

這個API是找到一個給定類名或者窗口名稱的窗口句柄。參數就不用介紹了,顧名思義,第一個參數就是窗口類名稱,第二個參數就是窗口名稱。我們在這裡只是用第二個參數。第一個參數放NULL。窗口名稱我們可以通過Spy++去獲取這是VS的一個工具:

遊戲外掛之進程鉤子

打開這個工具。

遊戲外掛之進程鉤子

將那個圓拖到遊戲標題欄後鬆開我們就可以看到這個遊戲窗口的標題了。我們根據這個標題去找窗口句柄。

DWORD GetWindowThreadProcessId( HWND hWnd, LPDWORD lpdwProcessId );

這個API返回創建指定窗口的線程ID,MSDN上這樣說的 “This function retrieves the identifier of the thread that created the specified window and, optionally, the identifier of the process that created the window”

參數hWnd是窗口句柄。就是FindWindow函數返回的值。lpdwProcessId是創建窗口的進程標誌ID,它是一個輸出參數,也就是一個指針。就和C#中的out參數差不多。這個參數可以放NULL,如果不是NULL,它會返回創建指定窗口的進程標誌。

HHOOK SetWindowsHookEx( int idHook,HOOKPROC lpfn,HINSTANCE hMod, DWORD dwThreadId);

這個API就是設置鉤子。第一個參數是鉤子類型。鉤子類型具體有哪些可以參照MSDN這裡我們用到的是WH_KEYBOARD。第二個參數就是一個回調函數。回調函數的格式如下:

LRESULT CALLBACK KeyboardProc( int code,
WPARAM wParam,
LPARAM lParam
);

第三個參數就是DLL的模塊句柄,我們可以通過API函數來獲取

HMODULE GetModuleHandle( LPCTSTR lpModuleName);

這個時候大家就會疑惑了SetWindowsHookEx的第三個參數是HINSTANCE類型,但是GetModuleHandle返回的卻是HMODULE,這個能對上嗎?其實能對上。你可以看看定義它的頭文件,我們能看到typedef HINSTANCE HMODULE 這樣大家就很容易看出它們其實就是一個東西。這在Windows 核心編程中經常碰到這種情況。我們在寫Windows遊戲外掛的時候,最好要去研究下Windows 核心編程。推薦一本比較耐看的書《windows核心編程》,我的是最新版.這本書的作者絕對Windows系統有很高的研究。值得反覆去看,去研究。不跑題了,繼續……。GetModuleHandle的第一個參數就是要注入的DLL路徑可以是相當也可以絕對,當然我推薦相對路徑。SetWindowsHookEx的最後一個參數就是GetWindowThreadProcessId返回的值。通過這樣的講解大家應該瞭解了。

下面就是實實在在的編碼。我們新建一個MFC DLL(我這個DLL的名稱是GameHookDLL)。

///鉤子回調函數
LRESULT CALLBACK KeyboardProc( int code, // hook code
WPARAM wParam, // virtual-key code
LPARAM lParam // keystroke-message information
){
AFX_MANAGE_STATE(AfxGetStaticModuleState());
if(wParam==VK_F1&&((lParam&(1<<31))==0)){
AfxMessageBox(L"F1鍵在遊戲窗口被按下了!");
}
return CallNextHookEx(0,code,wParam,lParam);
}
//(LPWSTR)"YB_OnlineClient"
void SetHook(LPWSTR prc_name){
AFX_MANAGE_STATE(AfxGetStaticModuleState());
HWND hd=FindWindow(NULL,prc_name);
if(hd==NULL)
{
AfxMessageBox(L"請打開輸入的程序進程");
return;
}
DWORD dwid=GetWindowThreadProcessId(hd,NULL);
//
HINSTANCE hdll=::GetModuleHandleW(L"GameHookDLL.dll");

SetWindowsHookEx(WH_KEYBOARD,&KeyboardProc,hdll,dwid);
}

這是我在DLL中添加的兩個函數,上面是SetWindowsHookEx的回調處理函數。對了,這個回調函數一定別忘了最後一行

return CallNextHookEx(0,code,wParam,lParam);如果回調KeyboardProc 中的code值小於0它會跳過去然後call下一個消息MSDN中的原文是:If code is less than zero, the hook procedure must pass the message to the CallNextHookEx function without further processing and should return the value returned by CallNextHookEx。所以我建議還是自己研究MSDN,比較我個人能力有限,說不定理解的有誤,當然在這裡如果有什不正確或者理解有偏差的地方希望大家諒解。這裡我們DLL只需要對外暴露第二個函數void SetHook(LPWSTR prc_name)。至於怎麼暴露,自己去看第二節。

if(wParam==VK_F1&&((lParam&(1<<31))==0)){
AfxMessageBox(L"F1鍵在遊戲窗口被按下了!");
}
wParam==VK_F1表示我們按下的F1鍵。(lParam&(1<<31))==0對lParam參數不熟悉的就不好理解了。lParam的第31位如果是0表示按下,如果是1表示按鍵彈起。我們這裡是判斷F1按鍵被按下。
如果沒有(lParam&(1<<31))==0我們按下F1鍵將會彈出兩次,一次是按下時彈出,一次是F1彈起式彈出。所以要保證lParam的第31位是0我們才彈出對話框。1<<31是10000000000000000000
0000000000後面有31個0而lParam的0~30位我們不確定但是我們&一下肯定都是0,然後第31位是0最後結果肯定是0這樣就實現了判斷。

MSDN中遠英文是:

lParam[in] Specifies the repeat count, scan code, extended-key flag, context code, previous key-state flag, and transition-state flag. For more information about the lParam parameter, see Keystroke Message Flags. This parameter can be one or more of the following values.

0-15.Specifies the repeat count. The value is the number of times the keystroke is repeated as a result of the user's holding down the key.

16-23.Specifies the scan code. The value depends on the OEM.

24.Specifies whether the key is an extended key, such as a function key or a key on the numeric keypad. The value is 1 if the key is an extended key; otherwise, it is 0.

25-28.Reserved.

29.Specifies the context code. The value is 1 if the ALT key is down; otherwise, it is 0.

30.Specifies the previous key state. The value is 1 if the key is down before the message is sent; it is 0 if the key is up.

31.Specifies the transition state. The value is 0 if the key is being pressed and 1 if it is being released.

接下來我們去新建一個MFC exe程序。在這個程序中去調用這個void SetHook(LPWSTR prc_name)函數。把窗口名稱作為參數傳過去。這裡我添加的是MFC 簡單對話框。對話框的佈局如圖:

遊戲外掛之進程鉤子

然後給文本框關聯上CString類型的變量txt_prc_name。在按鈕事件中添加註冊鉤子代碼:

void CGameWGClientDlg::OnBnClickedOk()
{
UpdateData(true);
LPWSTR s1=(LPWSTR)(LPCTSTR)txt_prc_name;
SetHook(s1);
// TODO: 在此添加控件通知處理程序代碼
//CDialogEx::OnOK();
}

這些只需要你掌握一點MFC知識。LPWSTR s1=(LPWSTR)(LPCTSTR)txt_prc_name;這個經過兩次裝換,主要是CString類型沒法直接裝換成LPWSTR類型。所以就這樣處理了。好代碼搞定,來看效果:

遊戲外掛之進程鉤子

在MFC客戶程序中輸入我們用Spy++找出的遊戲窗口名稱,然後點擊確定這樣鉤子就被註冊到了遊戲進程中。這時候我們在登陸框中隨便輸入,直到我們輸入F1彈出對話框。這樣通過鍵盤鉤子注入進程的原型就搞定了。這一節就到這裡。

作者:egojit

原文:https://www.cnblogs.com/egojit/archive/2013/06/16/3138266.html

"

相關推薦

推薦中...