做了一个监视线程消息的钩子函数,设置为系统钩子时可运行,但设置为线程钩子则无法运行,不知道为什么?

goldencz 2004-09-19 02:10:27
根据返回值判断,线程钩子已经加载成功了,但是就是拦截不到任何消息,不知道为什么会这样?
...全文
206 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
kugou123 2004-09-21
  • 打赏
  • 举报
回复
用跨进程的子类化技术可以实现。我有一篇文章资料:

用跨进程子类化技术实现对其它进程消息的拦载

作者:pankun(原作) 文章来源:黑防书籍 点击数: 83 更新时间:2004-4-26
转贴于 华夏黑客同盟 http://www.77169.org

大家都知道每个窗口都有默认的窗口函数来进行对窗口消息的处理.
而子类化技术就是替换窗口的窗口函数为自己定义的函数的技术.例如下面的代码:
var
Form1: TForm1;
OldWndProc: Pointer;
implementation

{$R *.dfm}
function NewWndProc(hHwnd, Msg, wParam, lParam: LongWORD): Longint; stdcall;
begin
if Msg=WM_CLOSE then
exit;
Result := CallWindowProc(OldWndProc, hHwnd, Msg, wParam, lParam);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
{保存旧的窗口函数地址}
OldWndProc := Pointer(GetWindowLong(Self.Handle, GWL_WNDPROC));
{设置新的窗口函数为自定义函数}
SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(@NewWndProc));
end;
这样在窗口建立时就对窗口实现了子类化,这时按下窗口的关闭按钮就会发现关不了窗口,因为新的窗口处理函数把WM_CLOSE消息过滤掉了,要取消子类化,只需要简单的把以前的窗口函数恢复过来就可以了.SetWindowLong(Self.Handle, GWL_WNDPROC, Longint(OldWndProc));[NextPage]

现在看来似乎很简单,只要对其它进程中的目标窗口进行子类化就可以实现对其消息的拦载监视了.但是在WIN32下,每一个进程都有自己独立的内存空间,新的窗口函数必须和目标窗口在同一个进程内,直接使用SetWindowLong(其它进程中窗口的句柄, GWL_WNDPROC, 新窗口函数)就会失败,所以就要想办法把我们的窗口函数代码放到目标进程内,这儿有二个办法,一是使用CreateRemoteThread在目标进程内建立线程,但这函数只在NT及以上操作系统实现,而且还要涉及到API地址重定位等问题,很麻烦(请参考http://www.csdn.net/develop/Read_Article.asp?Id=21079).另一个方法就是使用HOOK技术(SetWindowsHookEx,如果不知道,请先参考HOOK技术方面的文章),大家都知道,对其它进程进行HOOK时,此进程会自动加载HOOK过程所在的DLL,如果我们把窗口函数也放在DLL中,那窗口函数就相当于加载到了目标进程的地址空间中了,这方法简单易行.在这里我们就采用HOOK技术来实现跨进程子类化.

最后一个问题是如何在DLL中实现全局变量,因为DLL中的变量在每个进程加载这个DLL时都申请新的空间来存放变量,所以DLL中的变量在各个进程内不一样,可以利用内存文件映射,WM_COPYDATA等方法来实现全局变量.这儿采用内存文件映射.

现在需要的知识都已了解了,就让我们来看具体的代码吧(这儿是把所有函数放在一个DLL中):
library Hook;

uses
SysUtils,windows, Messages;

const
WM_UNSUBCLASS = WM_USER + 1001; {卸载子类化消息}
WM_NEWMESSAGE = WM_USER + 1002; {通知监视窗口拦到了新消息}
HOOK_EVENT_NAME = 'MyHook';

type
PMyDLLVar = ^TMyDLLVar;
TMyDLLVar = record
SubClass: Boolean; {是否已经子类化}
HookWindow, SpyWindow: LongWORD; {要安装HOOK的窗口及用于接收消息的窗口}
hHook: LongWORD; {HOOK句柄}
OldWndProc: pointer; {旧的窗口过程}
MsgHwnd: LongWORD;
Msg: TMessage;
end;

var
DLLData: PMyDLLVar;

{---------------------------------------}
{函数名:NewWndProc
{函数功能:新的窗口过程
{函数参数:hHwnd:窗口句柄 Msg:消息ID
{ wParam, lParam:消息参数
{函数返回值:下一个窗口过程的返回值
{---------------------------------------}
function NewWndProc(hHwnd, Msg, wParam, lParam: LongWORD): Longint; stdcall;
begin
if Msg = WM_UNSUBCLASS then {如果收到卸载子类化消息就恢复以前的WndProc}
begin
SetWindowLong(DLLData^.HookWindow, GWL_WNDPROC, longint(DLLData^.OldWndProc));
exit;
end;
{这儿是把收到的消息放在映射的内存中,我们自己的程序可以通过读这个内存来得到监视到的消息.}
DLLData^.Msg.Msg := Msg;
DLLData^.Msg.WParam := wParam;
DLLData^.Msg.LParam := lParam;
DLLData^.MsgHwnd := hHwnd;
{给监视窗口发送拦载新消息的消息}
SendMessage(DLLData^.SpyWindow, WM_NEWMESSAGE, 0, 0);
{这儿可以添加自己对目标进程消息处理的代码,因为己经是在目标进程的地址空间内,现在可以为所
欲为 ^_^)[NextPage]
Result := CallWindowProc(DLLData^.OldWndProc, hHwnd, Msg, wParam, lParam);
end;

{------------------------------------}
{过程名:HookProc
{过程功能:HOOK过程
{过程参数:nCode, wParam, lParam消息的相
{ 关参数
{------------------------------------}
procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
var
hEvent: THandle;
begin
if not DllData^.SubClass then {如果此窗口未子类化}
begin {保存窗口过程地址并子类化}
if hEvent <> 0 then
begin
WaitForSingleObject(hEvent, INFINITE);
CloseHandle(hEvent);
end;
DLLData^.OldWndProc := pointer(GetWindowLong(DLLData^.HookWindow, GWL_WNDPROC));
SetWindowLong(DLLData^.HookWindow, GWL_WNDPROC, integer(@NewWndProc));
DLLData^.SubClass := True;
hEvent := OpenEvent(Synchronize, False, HOOK_EVENT_NAME);
end;
{调用下一个Hook}
CallNextHookEx(DLLData^.hHook, nCode, wParam, lParam);
end;


{------------------------------------}
{函数名:InstallHook
{函数功能:在指定窗口上安装HOOK
{函数参数:HWindow:要安装HOOK的窗口
{ SWindow:用于接收消息的窗口
{返回值:成功返回TRUE,失败返回FALSE
{------------------------------------}
function InstallHook(HWindow, SWindow: LongWORD):Boolean;stdcall;
var
ThreadID: LongWORD;
hEvent: THandle;
begin
Result := False;
DLLData^.hHook := 0;
DLLData^.HookWindow := HWindow;
DLLData^.SpyWindow := SWindow;
{得到指定窗口的线程ID}
ThreadID := GetWindowThreadProcessId(HWindow, nil);
{给指定窗口挂上钩子}
hEvent := CreateEvent(nil, True, False, HOOK_EVENT_NAME);
DLLData^.hHook := SetWindowsHookEx(WH_GETMESSAGE, @HookProc, Hinstance, ThreadID);
SetEvent(hEvent);
CloseHandle(hEvent);
if DLLData^.hHook > 0 then Result := True; {是否成功HOOK}
end;

{------------------------------------}
{过程名:UnHook
{过程功能:卸载HOOK
{过程参数:无
{------------------------------------}
procedure UnHook;stdcall;
begin
{发送卸载子类化消息给指定窗口}
SendMessage(DLLData^.HookWindow, WM_UNSUBCLASS, 0, 0);
DLLData^.SubClass := False;
{卸载Hook}
UnhookWindowsHookEx(DLLData^.hHook);
end;[NextPage]

{------------------------------------}
{过程名:DLL入口函数
{过程功能:进行DLL初始化,释放等
{过程参数:DLL状态
{------------------------------------}
procedure MyDLLHandler(Reason: Integer);
var
FHandle: LongWORD;
begin
case Reason of
DLL_PROCESS_ATTACH:
begin {建立文件映射,以实现DLL中的全局变量}
FHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, $ff, 'MYDLLDATA');
if FHandle = 0 then
if GetLastError = ERROR_ALREADY_EXISTS then
begin
FHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'MYDLLDATA');
if FHandle = 0 then Exit;
end else Exit;
DLLData := MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
if DLLData = nil then
CloseHandle(FHandle);
end;
DLL_PROCESS_DETACH:
if Assigned(DLLData) then
begin
UnmapViewOfFile(DLLData);
DLLData := nil;
end;
DLL_THREAD_ATTACH:;
DLL_THREAD_DETACH:;
end;
end;

{$R *.res}
exports
InstallHook, UnHook, HookProc;

begin
DLLProc := @MyDLLHandler;
MyDLLhandler(DLL_PROCESS_ATTACH);
end.

编译这个DLL,然后在我们的程序中加载这个DLL,并调用InstallHook(目标窗口句柄, 自己窗口句柄)就可 以实现对目标窗口消息的监视了(在接收到WM_NEWMESSAGE消息时读映射的内存),调用UnHook则可以卸载掉子类化和HOOK.具休的代码还请读者自行编写.


goldencz 2004-09-20
  • 打赏
  • 举报
回复
to laiyiling:
已经看过了,按windows核心编程上讲的做的

to xxedge(好钢用在刀刃上)
是的,截获另外一个进程的线程消息

oyljerry(☆勇敢的心☆)
kugou123(酷狗)(程序小混混)
回调函数根本不执行,或者只执行可怜的几次
goldencz 2004-09-20
  • 打赏
  • 举报
回复
SetWindowsHookEx(WH_CALLWNDPROC, CallWndProc, pInstance, id);
该函数放在dll中执行,dll attach给了目标进程执行.
但还是不行,偶尔能够执行几次,但和系统发给窗口的消息数量比,则几乎等于没有执行
goldencz 2004-09-20
  • 打赏
  • 举报
回复
特定窗口(其他进程)的各种系统消息,比如WM_PAINT等等,根据需要获取其中的信息
除了加钩子之外你有什么办法吗?就是类似于spy++的功能
DentistryDoctor 2004-09-20
  • 打赏
  • 举报
回复
你钩的什么函数?
kugou123 2004-09-20
  • 打赏
  • 举报
回复
讲讲你需要拦截什么消息,实现什么功能?
nwpulipeng 2004-09-20
  • 打赏
  • 举报
回复
帮顶中
kugou123 2004-09-19
  • 打赏
  • 举报
回复
检查一下你的回调函数,是不是把消息的处理给漏掉了。呵呵。
oyljerry 2004-09-19
  • 打赏
  • 举报
回复
你怎么截获的消息,自己检查看看
xxedge 2004-09-19
  • 打赏
  • 举报
回复
你想截获的消息是发给你的线程的么?
Kudeet 2004-09-19
  • 打赏
  • 举报
回复
仔细点慢慢查吧!
http://search.csdn.net/Expert/topic/2118/2118403.xml?temp=.1039087

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧