熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

淺談VB.NET中的跨進程消息鉤子

2022-06-13   來源: .NET編程 

  我們都知道在VB裡面可以用API函數來進行子類化以處理自身的窗體過程如果跨進程這就麻煩了由於我們的函數在我們的進程中(廢話)而目標進程的窗口的消息處理函數在目標進程(還是廢話)所以只能想辦法把我們的代碼放到對方進程中去執行——並且要告知我們的進程得到了什麼消息恐怕寫匯編就有點嚇人了於是大家都寫DLL其原理就是把回調函數放到一個DLL裡面注入到對方進程DLL去修改目標窗口的默認處理函數——把消息發送給我們

  當然也有另類一點的/ThueDownloads/indexshtml上面有一個DLL包其中含有一個dssubclsdll用它可以輕松的完成我們的工作就像調用一個API一樣簡單而且在我們的程序中使用回調函數!呵呵省去了自己寫DLL的麻煩之後這些好處足以吸引各位觀眾了吧?

  好了VB的代碼大家可以在下載的壓縮包中找到作者提供了一個以記事本為基礎的實例(在\dssubcls目錄下)非常詳細無需詳細敘述了關鍵是在VBNET裡面如何使用它——如何聲明API如何進行回調看用來子類化的API的VB聲明先

  Declare Function SubClass& Lib dssubcls (ByVal HwndSubclass& _
Optional ByVal Address& = _
Optional ByVal OldStyle& = _
Optional ByVal NewStyle& = _
Optional ByVal Ext& = _
Optional ByVal SubClass& = )
轉化成VBNET的聲明類似下面的樣子(習慣使然我把&展開成了As Integer)

  Declare Function SubClass Lib dssubcls (ByVal HwndSubclass As Integer Optional ByVal Address As Integer = Optional ByVal OldStyle As Integer = Optional ByVal NewStyle As Integer = Optional ByVal Ext As Integer = Optional ByVal SubClass As Integer = ) As Integer

  這不是很好嘛?問題來了這樣的聲明在VB裡面可以使用Addressof function來傳入第二個參數(參見你下載的源碼)但是在VBNET裡面直接Addressof就不成了——我們需要委托一個回調

  Private Delegate Function HookCallBack(ByVal wMsg As Integer ByVal wParam As Integer ByVal lParam As Integer) As Integer

  這個委托對應的是以下函數

  Private Function mCallback(ByVal wMsg As Integer ByVal wParam As Integer ByVal lParam As Integer) As Integer
在這裡處理得到的消息

  End Function

  使用時需要注意先實例化這個委托

  Private fix_COCD = New HookCallBack(AddressOf mCallback)

  此時fix_COCD就是我們的mCallback函數引用了用更直觀的觀點來看fix_COCD就是一個指向mCallback的指針相當於VB裡面的Addressof function得到的結果看似問題解決了於是我們寫了以下代碼來搞對方的進程窗體消息

  SubClass(Handle fix_COCD ) 修改處理函數

  問題真是接踵而至!IDE提示變量類型不符!!事實確實如此我們把一個HookCallBack類型當做Integer來傳遞無法通過檢查那麼強行轉換吧?當然你可以去試試這時我所做的是修改這個API聲明

  Private Declare Function SubClass Lib dssubcls (ByVal HwndSubclass As Integer Optional ByVal Address As HookCallBack = Nothing Optional ByVal OldStyle As Integer = Optional ByVal NewStyle As Integer = Optional ByVal Ext As Integer = Optional ByVal SubClass As Integer = ) As Integet

  使之符合我們的調用?有點倒行逆施?並非如此當你習慣了修改API聲明之後會發現有些事變得如此簡單有些事需要你重新認識——對於WIN API也是如此

  至此大功告成

  較為完整的代碼如下

  Code
Private Declare Function SubClass Lib dssubcls (ByVal HwndSubclass As Integer Optional ByVal Address As HookCallBack = Nothing Optional ByVal OldStyle As Integer = Optional ByVal NewStyle As Integer = Optional ByVal Ext As Integer = Optional ByVal SubClass As Integer = ) As Integer
Private Declare Function UseSendMessage Lib dssubcls (ByVal use As Integer) As Integer
實例化的委托
Private fix_COCD = New HookCallBack(AddressOf mCallback)
委托
Private Delegate Function HookCallBack(ByVal wMsg As Integer ByVal wParam As Integer ByVal lParam As Integer) As Integer
Public Sub Hook(ByVal Handle As Integer)
proc = SubClass(Handle fix_COCD ) 修改處理函數
UseSendMessage()
End Sub

  Private Function mCallback(ByVal wMsg As Integer ByVal wParam As Integer ByVal lParam As Integer) As Integer

  End Function

  用這個代碼的時候可能會碰見一些意外情況例如wm_datacopy此時我們需要進一步去獲取LPARTM所指向的結構並對其進行解析(我們要讀的是對方窗口所在進程的內存具體地址由lParam確定——實際上lParam一直是一個指針——IntPrt但它與Integer完全就是一回事(如果你使用VB可能需要使用Intprttoint或intprt=new intprt(integer)這些)

  Code
Public Class GetMsg
Public Declare Function ReadProcessMemory Lib kernel (ByVal hProcess As Integer ByVal lpBaseAddress As Integer ByVal lpBuffer() As Byte ByVal nSize As Integer ByRef lpNumberOfBytesWritten As Integer) As Integer
Public Declare Function ReadProcessMemory Lib kernel (ByVal hProcess As Integer ByVal lpBaseAddress As Integer ByRef int As Integer ByVal nSize As Integer ByRef lpNumberOfBytesWritten As Integer) As Integer
Public Declare Function OpenProcess Lib kernel (ByVal dwDesiredAccess As Integer ByVal bInheritHandle As Integer ByVal dwProcessId As Integer) As Integer
Public Declare Function CloseHandle Lib kernel (ByVal hObject As Integer) As Integer
Private hProc As IntPtr
Sub New(ByVal PID As Integer)
hProc = OpenProcess(&HFFFF False PID)
End Sub

  Function readmsg(ByVal address As Integer) As Byte()
Dim buf() As Byte
ReadProcessMemory(hProc address buf )
Return buf
End Function

  Protected Overrides Sub Finalize()
CloseHandle(hProc)
MyBaseFinalize()
End Sub
End Class
這個類提供了Readmsg方法來讀取一些內容——但這並不是完整的我們知道LPARAM指向的結構是這樣的

  _
Public Structure COPYDATASTRUCT
Public dwData As Integer
Public cbData As Integer
Public lpData As IntPtr
End Structure

  其中dwData我們不是很關心當然其中也可能存在一些有用信息(這裡不想多說網上有些文章純屬誤導)

  而cbData是一個長度lpData的長度

  lpData這裡被聲明為指針看起來更直觀了——它就是地址

  有了地址和長度如何讀取代碼就自己寫吧

  提示一下參考我重載的ReadProcessMemory可能對你有不少幫助

  當然上面提到的只是特殊情況中的一個典型還有很多時候進程是用自定義消息(>&HA)來傳遞數據的例如我所開發的這個工程打印mCallBack的參數後得到的是如下結果(十六進制只提取了有用的信息)

  D

  其中lParam就是一個指針我讀了其中的一部分

  Function readmsg(ByVal address As Integer) As Byte()
Dim buf() As Byte
ReadProcessMemory(hProc address buf )
Return buf
End Function

  現在就明白為什麼上面的代碼是那樣了

  然後進行了一個處理得到了我想要的信息

  消息解碼後得到的移動棋子信息玩家起X起Y止X止Y棋子編號

  走棋總步數
Event Move(ByVal player As Byte ByVal sx As Byte ByVal sy As Byte ByVal dx As Byte ByVal dy As Byte ByVal name As Byte ByVal [step] As Byte)
Private Function mCallback(ByVal wMsg As Integer ByVal wParam As Integer ByVal lParam As Integer) As Integer
If wParam = &H Then
Dim s As Byte() = msgreadmsg(lParam)
RaiseEvent Move(s() s() s() s() s() s() s())
End If
End Function

  當然在我的工程裡面重載的ReadProcessMemory並沒有被使用

  補充一下咯

  在VBNET中處理自己的窗體的消息只需要重載窗體消息處理過程就可以了無需子類化

  有補充一下

  對於wm_datacopy來說還有一些數據獲取的問題沒有說清楚實際上都可以用一些方法來解決


From:http://tw.wingwit.com/Article/program/net/201311/12647.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.