就是一个很简单的hook,也没做什么特殊的事情,卸载的时候就导致错误。
dll主要代码:
var HookHandle: THandle;
function GetMsgProc(nCode: Integer; WParam: WPARAM; LParam: LPARAM): Integer; stdcall;
begin
Result := CallNextHookEx(HookHandle, nCode, WParam, LParam);
end;
procedure StartHook; stdcall;
begin
HookHandle := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, HInstance, 0);
end;
procedure StopHook; stdcall;
begin
UnhookWindowsHookEx(HookHandle);
end;
end;
exports StartHook, StopHook;
begin
API_Hookup; //加载时挂上
end.
在另外一个pas中
procedure API_Hookup;
procedure Un_API_Hook;
implementation
procedure API_Hookup;
beginend;
procedure Un_API_hook;
begin
end;
initializationfinalization
Un_API_hook;
end.
在一个test.exe中,有两个按钮,分别启动钩子和卸载钩子
procedure TForm1.Button1Click(Sender: TObject);
begin
StartHook;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
StopHook;
end; 就这么简单。运行test.exe之前,先把任务管理器(taskmgr.exe)窗口打开,然后执行test.exe,先点击按钮1启动钩子,再点击按钮2卸载钩子。
这个时候再随便打开一个文本文件,如果是用系统默认的notepad就一切正常,但如果是用editplus之类的打开,就提示任务管理器错误。如果没开任务管理器,则可能导致其他程序错误,比如我刚刚写这个问题的IE出现错误,被关掉,导致我重新写了一遍。
本来我的hook里是有些功能的,但是卸载钩子,总是导致explorer.exe出错,就是资源管理器出错,总是把所有打开的文件夹关闭并重新刷新桌面,也就是资源管理器出错后,重新加载资源管理器。我就把代码一点点注释掉,最后注释到就向我说的这么简单,结果现在发现总是导致任务管理器错误了。
在别的机器上试也是这样。
谁能说清楚怎么回事?
dll主要代码:
var HookHandle: THandle;
function GetMsgProc(nCode: Integer; WParam: WPARAM; LParam: LPARAM): Integer; stdcall;
begin
Result := CallNextHookEx(HookHandle, nCode, WParam, LParam);
end;
procedure StartHook; stdcall;
begin
HookHandle := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, HInstance, 0);
end;
procedure StopHook; stdcall;
begin
UnhookWindowsHookEx(HookHandle);
end;
end;
exports StartHook, StopHook;
begin
API_Hookup; //加载时挂上
end.
在另外一个pas中
procedure API_Hookup;
procedure Un_API_Hook;
implementation
procedure API_Hookup;
beginend;
procedure Un_API_hook;
begin
end;
initializationfinalization
Un_API_hook;
end.
在一个test.exe中,有两个按钮,分别启动钩子和卸载钩子
procedure TForm1.Button1Click(Sender: TObject);
begin
StartHook;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
StopHook;
end; 就这么简单。运行test.exe之前,先把任务管理器(taskmgr.exe)窗口打开,然后执行test.exe,先点击按钮1启动钩子,再点击按钮2卸载钩子。
这个时候再随便打开一个文本文件,如果是用系统默认的notepad就一切正常,但如果是用editplus之类的打开,就提示任务管理器错误。如果没开任务管理器,则可能导致其他程序错误,比如我刚刚写这个问题的IE出现错误,被关掉,导致我重新写了一遍。
本来我的hook里是有些功能的,但是卸载钩子,总是导致explorer.exe出错,就是资源管理器出错,总是把所有打开的文件夹关闭并重新刷新桌面,也就是资源管理器出错后,重新加载资源管理器。我就把代码一点点注释掉,最后注释到就向我说的这么简单,结果现在发现总是导致任务管理器错误了。
在别的机器上试也是这样。
谁能说清楚怎么回事?
解决方案 »
- Delphi怎么调用函数接口?
- 网页调用封装在dll中delphi开发的窗体(类似功能,也可能不是这们实现的)请进来看(100分)
- fastreport 多个page 页码显示问题?
- 自己设计一个简单的报表编辑工具遇到的控件拖放问题
- 一个关于数据库的简单问题,大家进来看看!!在线等着!!
- c 代码 转 delphi
- 如何知道Windows 中的某个窗口被Paint了,及Paint了什么?
- 一个关于Form展现的问题。
- 有谁能详细解释一下procedure中sender的意义及用法?谢谢!
- 怎样取richedit中的第一个字符的位置(不包括空字符)
- 【to-all】2009能否让delphi再复生机?
- 用delphi5编的一个多线程程序包内存错
因为你的dll会被多个进程加载,除了test.exe装载的那个dll中的HookHandle是正确的,其他进程的HookHandle都是0,因此CallNextHookEx(HookHandle, nCode, WParam, LParam)的参数HookHandle并不正确。
改成Result := CallNextHookEx(0, nCode, WParam, LParam);
但同样还是会出现我描述的现象。
之后,explorer.exe不出错了。但任务管理器还是出错。
HookHandle := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, 0, GetCurrentThreadId);
能说说你这样写和我那样写的区别吗?谢谢
我查了一下,如果用GetCurrentThreadId表示钩住当前线程。
但我是要监视整个系统的消息,而且是写在Dll中,所以应该不能用GetCurrentThreadId吧?
这样写试试看
你是不是有问题啊,就会引用别人的回复啊?
我几个帖子里,你都这么回复,有意义吗?
DLL部分:
library makeErr;uses
Messages,
Classes,
SysUtils,
Windows,
Dialogs,
ComServ,
theMain in 'theMain.pas';exports
DllGetClassObject,
DllCanUnloadNow,
DllRegisterServer,
DllUnregisterServer;{$R *.RES}var HookHandle: THandle;
hookFlag : Boolean;
function GetMsgProc(nCode: Integer; WParam: WPARAM; LParam: LPARAM): Integer; stdcall;
begin
Result := CallNextHookEx(HookHandle, nCode, WParam, LParam);
end;
procedure StartHook; stdcall;
begin
if not hookFlag then
begin
HookHandle := SetWindowsHookEx(WH_CALLWNDPROC, @GetMsgProc, HInstance, 0);
hookFlag := true;
end;
end;
procedure StopHook; stdcall;
begin
if hookFlag then
begin
UnhookWindowsHookEx(HookHandle);
hookFlag := false;
end;
end;exports StartHook, StopHook;
begin
API_Hookup; //加载时挂上
end.theMain.pas
unit theMain;interfaceprocedure API_Hookup;
procedure Un_API_Hook;implementation
procedure API_Hookup;
beginend;
procedure Un_API_hook;
begin
end;
initializationfinalization
Un_API_hook;
end.调用DLL程序:
program makeErrApp;uses
Forms,
MainForm in 'MainForm.pas' {Form1};{$R *.res}begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.'MainForm.pas' 代码:
unit theMain;interfaceprocedure API_Hookup;
procedure Un_API_Hook;implementation
procedure API_Hookup;
beginend;
procedure Un_API_hook;
begin
end;
initializationfinalization
Un_API_hook;
end.
SysUtils,
windows,
Messages,
Apihook in 'Apihook.pas';var
DLLHook: HHOOK;
Bol: Boolean = False;procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
begin
if not Bol then
CallNextHookEx(DLLHook, nCode, wParam, lParam);
end;{ 状态挂钩 }
function InstallHook(MainHandle: HWND): Boolean; stdcall;
begin
DLLHook := SetWindowsHookEx(WH_GETMESSAGE, @HookProc, Hinstance, 0);
Result := DLLHook <> 0;
end;{ 卸载挂钩 }
procedure UnHook; stdcall;
begin
UnHookAPI;
UnhookWindowsHookEx(DLLHook);
end;procedure MyDLLHandler(Reason: Integer);
begin
case Reason of
DLL_PROCESS_ATTACH: HookAPI;
DLL_PROCESS_DETACH: UnHook;
end;
end;exports
InstallHook;begin
DLLProc := @MyDLLHandler;
MyDLLhandler(DLL_PROCESS_ATTACH);
Bol := False;
end. 比下
SysUtils, Windows, TlHelp32, Dialogs;type
{ 要HOOK的API函数定义 }
TMyOpenProcess = function (dwDesiredAccess: DWORD; bInheritHandle:
BOOL; dwProcessId: DWORD): THandle; stdcall; procedure HookAPI;
procedure UnHookAPI;var
ProcessHandle: HWND;
BaseAddress: Pointer;
MainHooK: Cardinal;
OldProc: array [0..7] of Byte;
NewPorc: array [0..7] of Byte;
implementationfunction GetFileName(dwProcessID: Cardinal): string;
var
me: MODULEENTRY32;
hm: Thandle;
begin
hm := CreateToolHelp32SnapShot(TH32CS_SNAPmodule, dwProcessID);
me.dwSize := sizeof(ModuleEntry32);
Module32First(hm, me);
Result := StrPas(@me.szExePath);
end;function MyOpenProcess(dwDesiredAccess: DWORD; bInheritHandle:
BOOL; dwProcessId: DWORD): THandle; stdcall;
const
INPMCLASS = 'TButForm1';
var
nSize :Cardinal;
Hwnds: HWND;
AppProID: DWORD;
begin
if dwDesiredAccess = PROCESS_TERMINATE then
begin
Hwnds := FindWindow(INPMCLASS, nil);
if Hwnds <> 0 then
begin
GetWindowThreadProcessId(Hwnds, @AppProID);
if dwProcessId = AppProID then
begin
Result := 0;
Exit;
end;
end;
end;
WriteProcessMemory(ProcessHandle, BaseAddress, @OldProc, 8, nSize);
Result := OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
WriteProcessMemory(ProcessHandle, BaseAddress, @NewPorc, 8, nSize);
end;procedure HookAPI();
var
DLLModule: THandle;
nSize: Cardinal;
Dat: DWORD;
Tmp : array [0..3] of Byte;
begin
ProcessHandle := GetCurrentProcess;
DLLModule := LoadLibrary('kernel32.dll');
{ 系统函数入口点地址 }
BaseAddress := GetProcAddress(DLLModule, 'OpenProcess');
Dat := DWORD(@MyOpenProcess);
Move(Dat, Tmp, 4);
NewPorc[0] := $B8; { 汇编跳转指令 }
NewPorc[1] := Tmp[0]; { 跳转到自身的函数 }
NewPorc[2] := Tmp[1];
NewPorc[3] := Tmp[2];
NewPorc[4] := Tmp[3];
NewPorc[5] := $FF;
NewPorc[6] := $E0;
NewPorc[7] := 0;
{ 读取系统函数内存地址 }
if ReadProcessMemory(ProcessHandle, BaseAddress, @OldProc, 8, nSize) then
{ 用自己的函数地址覆盖系统的函数地址 }
if WriteProcessMemory(ProcessHandle, BaseAddress, @NewPorc, 8, nSize) then
end;procedure UnHookAPI;
var
nSize: Cardinal;
begin
{ 恢复所修改的地址 }
WriteProcessMemory(ProcessHandle, BaseAddress, @OldProc, 8, nSize);end;end.
1、这个Dll在XP里,我刚一挂钩就出错,好像是改地址的时候出错。
2、这个Hook的卸载在哪触发啊?就是说什么时候会传递给MyDLLHandler那个卸载参数DLL_PROCESS_DETACH?
3、Bol 变量好像永远都是False,是不是可以不定义呢?还是有特别的含义?
原因是function InstallHook(MainHandle: HWND): Boolean; stdcall; 里面不应该有那个参数
2、这个Hook的卸载在哪触发啊?就是说什么时候会传递给MyDLLHandler那个卸载参数DLL_PROCESS_DETACH?
DLLProc := @MyDLLHandler;会自动触发MyDLLHandler,并传递参数DLL_PROCESS_DETACH。
library makeErr;
uses
SysUtils,
windows,
Messages,
Dialogs,
Apihook in 'Apihook.pas';var
DLLHook: HHOOK;
Bol: Boolean = False; procedure HookProc(nCode, wParam, lParam: LongWORD);stdcall;
begin
if not Bol then
CallNextHookEx(DLLHook, nCode, wParam, lParam);
end; { 状态挂钩 }
function InstallHook(): Boolean; stdcall;
begin
DLLHook := SetWindowsHookEx(WH_GETMESSAGE, @HookProc, Hinstance, 0);
Result := DLLHook <> 0;
end; { 卸载挂钩 }
procedure UnHook; stdcall;
begin
UnHookAPI;
UnhookWindowsHookEx(DLLHook);
end;procedure MyDLLHandler(Reason: Integer);
begin
case Reason of
DLL_PROCESS_ATTACH: HookAPI;
DLL_PROCESS_DETACH: UnHook;
end;
end; exports
InstallHook; begin
DLLProc := @MyDLLHandler;
MyDLLhandler(DLL_PROCESS_ATTACH);
Bol := False;
end.unit Apihook;interface uses
SysUtils, Windows, TlHelp32, Dialogs;
{
type
//要HOOK的API函数定义
TMyOpenProcess = function (dwDesiredAccess: DWORD; bInheritHandle:
BOOL; dwProcessId: DWORD): THandle; stdcall;
} procedure HookAPI;
procedure UnHookAPI;
{
var
ProcessHandle: HWND;
BaseAddress: Pointer;
MainHooK: Cardinal;
OldProc: array [0..7] of Byte;
NewPorc: array [0..7] of Byte; }
implementation
{
function GetFileName(dwProcessID: Cardinal): string;
var
me: MODULEENTRY32;
hm: Thandle;
begin
hm := CreateToolHelp32SnapShot(TH32CS_SNAPmodule, dwProcessID);
me.dwSize := sizeof(ModuleEntry32);
Module32First(hm, me);
Result := StrPas(@me.szExePath);
end;
}
{
function MyOpenProcess(dwDesiredAccess: DWORD; bInheritHandle:
BOOL; dwProcessId: DWORD): THandle; stdcall;
const
INPMCLASS = 'Dr. Watson for Windows';
var
nSize :Cardinal;
Hwnds: HWND;
AppProID: DWORD;
begin
if dwDesiredAccess = PROCESS_TERMINATE then
begin
Hwnds := FindWindow(INPMCLASS, nil);
if Hwnds <> 0 then
begin
GetWindowThreadProcessId(Hwnds, @AppProID);
if dwProcessId = AppProID then
begin
Result := 0;
Exit;
end;
end;
end;
WriteProcessMemory(ProcessHandle, BaseAddress, @OldProc, 8, nSize);
Result := OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
WriteProcessMemory(ProcessHandle, BaseAddress, @NewPorc, 8, nSize);
end;
}
procedure HookAPI();
{var
DLLModule: THandle;
nSize: Cardinal;
Dat: DWORD;
Tmp : array [0..3] of Byte; }
begin
{ProcessHandle := GetCurrentProcess;
DLLModule := LoadLibrary('kernel32.dll');
//系统函数入口点地址
BaseAddress := GetProcAddress(DLLModule, 'OpenProcess');
Dat := DWORD(@MyOpenProcess);
Move(Dat, Tmp, 4);
NewPorc[0] := $B8; //汇编跳转指令
NewPorc[1] := Tmp[0]; //跳转到自身的函数
NewPorc[2] := Tmp[1];
NewPorc[3] := Tmp[2];
NewPorc[4] := Tmp[3];
NewPorc[5] := $FF;
NewPorc[6] := $E0;
NewPorc[7] := 0;
//读取系统函数内存地址
if ReadProcessMemory(ProcessHandle, BaseAddress, @OldProc, 8, nSize) then
//用自己的函数地址覆盖系统的函数地址
if WriteProcessMemory(ProcessHandle, BaseAddress, @NewPorc, 8, nSize) then }
end; procedure UnHookAPI;
{var
nSize: Cardinal; }
begin
//恢复所修改的地址
//WriteProcessMemory(ProcessHandle, BaseAddress, @OldProc, 8, nSize); end; end.
挂钩程序
unit MainForm;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
procedure InstallHook; stdcall; external 'makeErr.dll';
// procedure UnHook; stdcall; external 'makeErr.dll';
var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
InstallHook;
end;procedure TForm1.Button2Click(Sender: TObject);
begin
// UnHook;
end;end.
多执行几次,就会发现我描述的问题。
而且,如果在执行程序前,先打开任务管理器(taskmgr.exe),执行挂钩程序后,在操作任务管理器,肯定出问题。
如果在桌面右键菜单,新建文件,打开,关掉,再开个文件夹,也会出错。
UNHOOK;就可以了调用的时候在FORM里
Procedure UnHook;External 'HOOK.dll';
或者
Procedure UnHook;External 'HOOK.dll' name 'UnHook';
if ModuleHandle = 0 then Exit;
@InstallHook := GetProcAddress(ModuleHandle, 'InstallHook');
if InstallHook(0) then
begin
//ShowMessage('安装HOOK成功,不知道OPENBROCESS咋样.');
end;
我发现好像不用导出unhook,而且你之前给我的示例代码里也确实没有显式调用unhook。而且在挂钩主程序退出的时候,unhook也确实被调用了。
运行了你的程序,发现确实没有问题。
还是我写的不对,我再按照你说的试试。
但我发现我必须按照你那样声明
InstallHook: function():Boolean; stdcall;
并且在使用之前
ModuleHandle := LoadLibrary('Hook.dll');
if ModuleHandle = 0 then Exit;
@InstallHook := GetProcAddress(ModuleHandle, 'InstallHook');
InstallHook;
才不会出错。
实在不理解为什么,我直接像unhook方法声明那样写
function InstallHook: Boolean; stdcall; external 'makeErr.dll';
就不行呢。
而且发现我这么写,hook是有效的,就是在unhook之后才出现资源管理器错误。只要钩子不退出,就不会出错。
能再解释一下吗?
看好多文章上都是像我写的那样介绍的啊。比如《Delphi下深入Windows核心编程》第二章就是这么讲的啊。
Delphi才边学边用几个月而已。
procedure UnHook; stdcall; external 'makeErr.dll';
为什么这个就没问题呢,而InstallHook却必须那么声明,为什么呢?
非常感谢。
改时间,再就我俩今天讨论的情况再开个高分的贴,等待高手继续出现。
unit MainForm;interfaceuses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
procedure StartHook; stdcall; external 'makeErr.dll';
procedure StopHook; stdcall; external 'makeErr.dll';
var
Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
StartHook;
end;procedure TForm1.Button2Click(Sender: TObject);
begin
StopHook;
end;end.