📄 uhook.pas
字号:
unit UHook;
interface
uses Windows, Messages, SysUtils, Controls, Menus, Forms;//, Dialogs;
type
TMyObject = class(TObject)
procedure MenuClick(Sender: TObject);
end;
procedure InstallHook(MainWnd, DestWnd: HWND); stdcall;
procedure UninstallHook; stdcall;
implementation
uses UShare;
var
ControlAtom: TAtom;
ControlAtomString: string;
RM_GetObjectInstance: DWORD; // 自定义的windows消息,供不同的进程间使用
MyObject: TMyObject;
procedure TMyObject.MenuClick(Sender: TObject);
begin
WinExec('notepad.exe', SW_NORMAL);
end;
//======================================================
//改造Delphi的FindControl函数
function FindControl(Handle: HWnd): TWinControl;
var
OwningProcess: DWORD;
begin
Result := nil;
if (Handle <> 0) and (GetWindowThreadProcessID(Handle, OwningProcess) <> 0) and
(OwningProcess = GetCurrentProcessId) then
begin
if GlobalFindAtom(PChar(ControlAtomString)) = ControlAtom then
Result := Pointer(GetProp(Handle, MakeIntAtom(ControlAtom)))
else
Result := Pointer(SendMessage(Handle, RM_GetObjectInstance, 0, 0));
end;
end;
//======================================================
//秘密窗口的回调函数,真正的工作就在这里
function MsgWndProc(hwnd: HWND; Msg: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
var
i: Integer;
aForm: TForm;
aMainMenu: TMainMenu;
aMenuItem: TMenuItem;
begin
case Msg of
WM_DESTROY: PostMessage(P^.HostWnd, WM_Close, 0, 0);
CM_BUILDMENU:
begin
Result := -1;
if P^.DestWnd <> 0 then
begin
//调用我们改进的FindControl函数来寻找待打补丁程序的主窗口,非常重要!!!!
aForm := Pointer(FindControl(P^.DestWnd));
if aForm <> nil then begin
//遍历窗体上的所有控件来定位主菜单,注意这里好像不能使用is和as操作符,只能用强制转换
for i := 0 to aForm.ComponentCount-1 do begin
//请在这里对你找到的控件进行处理
//下面是我对TMainMenu进行的处理
if aForm.Components[i].ClassName = 'TMainMenu' then begin
aMainMenu := TMainMenu(aForm.Components[i]);
if aMainMenu.Items.Count>1 then begin
aMenuItem := TMenuItem.Create(aForm);
aMenuItem.Caption := '新增菜单';
aMenuItem.OnClick := MyObject.MenuClick;
aMainMenu.Items[0].Add(aMenuItem);
end;
//Showmessage('增加菜单成功!')
Result := 1;
Break;
end;
end;
end;
end;
Exit;
end;
end;
Result := DefWindowProc(hwnd, Msg, WParam, LParam);
end;
//======================================================
//======================================================
//我们的钩子程序,实际上该钩子没起作用,它只是处理流程的一个必须步骤
function GetMsgProc(Code: UINT; WParam: WPARAM; LParam: LPARAM): LRESULT; stdcall;
begin
if Code = HC_ACTION then
begin
end;
Result := CallNextHookEx(P^.hkMsg, Code, WParam, LParam);
end;
//======================================================
//安装钩子,目的是让我们的dll注入到待打补丁应用程序所在的进程空间
procedure InstallHook(MainWnd, DestWnd: HWND); stdcall;
begin
if P^.hkMsg = 0 then
P^.hkMsg := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, HInstance, 0);
P^.HostWnd := MainWnd;
P^.HostPID := GetCurrentProcessId;
P^.DestWnd := DestWnd;
end;
//======================================================
//======================================================
//卸载钩子
procedure UninstallHook; stdcall;
begin
if P^.hkMsg <> 0 then
begin
UnhookWindowsHookEx(P^.hkMsg);
P^.hkMsg := 0;
end;
end;
//======================================================
var
DoClear: Boolean;
DestProcess: Boolean = False;
DestPID: DWORD;
//窗口类定义
UtilWindowClass: TWndClass = (
style: 0;
lpfnWndProc: @MsgWndProc;
cbClsExtra: 0;
cbWndExtra: 0;
hInstance: 0;
hIcon: 0;
hCursor: 0;
hbrBackground: 0;
lpszMenuName: nil;
lpszClassName: 'THook_Hxb_leiyuan');
initialization
//======================================================
// 建立内存镜像文件,供不同的进程来交换数据
hMapFile := OpenFileMapping(FILE_MAP_WRITE, False, cMapFileName);
DoClear := hMapFile = 0;
if hMapFile = 0 then
hMapFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE,
0, SizeOf(TShareData), cMapFileName);
P := MapViewOfFile(hMapFile, FILE_MAP_WRITE, 0, 0, 0);
if DoClear then FillChar(P^, SizeOf(TShareData), 0);
//======================================================
//======================================================
// 为不同的进程定义不同的windows消息,该消息将与调用进程绑定,特别要注意GetModuleHandle(nil)的使用
ControlAtomString := Format('ControlOfs%.8X%.8X', [GetModuleHandle(nil), GetCurrentThreadID]);
ControlAtom := GlobalAddAtom(PChar(ControlAtomString));
RM_GetObjectInstance := RegisterWindowMessage(PChar(ControlAtomString)); //注册消息,供不同的进程间使用
//======================================================
//======================================================
// 为待打补丁的程序所属的进程创建一个秘密窗口,该窗口是属于待打补丁的程序的(即它们在同一个进程空间),
// 利用该秘密窗口,外界就可以来指挥待打补丁的程序
if P^.DestWnd <> 0 then
begin
GetWindowThreadProcessId(P^.DestWnd, DestPID);
if DestPID = GetCurrentProcessId then
begin
DestProcess := True;
UtilWindowClass.hInstance := HInstance;
RegisterClass(UtilWindowClass);
P^.MsgWnd := CreateWindowEx(
WS_EX_TOOLWINDOW, // extended window style
UtilWindowClass.lpszClassName, // pointer to registered class name
UtilWindowClass.lpszClassName, // pointer to window name
WS_POPUP, // window style
0, // horizontal position of window
0, // vertical position of window
0, // window width
0, // window height
0, // handle to parent or owner window
0, // handle to menu, or child-window identifier
HInstance, // handle to application instance
nil); // pointer to window-creation data
PostMessage(P^.HostWnd, CM_MSGWNDCREATED, P^.MsgWnd, 1);
end;
end;
//======================================================
finalization
if DestProcess then
begin
DestroyWindow(P^.MsgWnd);
PostMessage(P^.HostWnd, CM_MSGWNDCREATED, P^.MsgWnd, 0);
end;
GlobalDeleteAtom(ControlAtom);
ControlAtomString := '';
UnmapViewOfFile(P);
CloseHandle(hMapFile);
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -