这是我以前Down的一个,基本没了一下,没有错<br>以下是代码:<br>{Dll部分}<br>library GetWordDll;<br><br>uses<br> Windows,<br> SysUtils,<br> Classes,<br> UnitHookDll in 'UnitHookDll.pas',<br> UnitNt2000Hook in 'UnitNt2000Hook.pas',<br> UnitHookType in 'UnitHookType.pas';<br><br>exports<br> StartHook,<br> StopHook,<br>// MouseWndProc,<br> {以下导出列表都是必须的,<br> 不能少,因为程序要取其地址}<br> NewBeginPaint,<br> NewCreateCompatibleDC,<br> NewTextOutA,<br> NewTextOutW,<br> NewExtTextOutA,<br> NewExtTextOutW,<br> NewDrawTextA,<br> NewDrawTextW; <br>begin<br>end.<br><br><br>unit UnitHookDll;<br><br>interface<br><br>uses Windows, SysUtils, Classes, math, messages, dialogs, UnitNt2000Hook,<br> UnitHookType;<br><br>const<br> COLOR1=255;<br> COLOR2=0;<br> COLOR3=255;<br> Trap=true; //True陷阱式,False表示改引入表式<br><br> procedure StartHook; stdcall; {开始取词}<br> procedure StopHook; stdcall; {停止取词}<br> function NewBeginPaint(Wnd: HWND; var lpPaint: TPaintStruct): HDC; stdcall;<br> function NewCreateCompatibleDC(DC: HDC): HDC; stdcall;<br> function NewTextOutA(theDC: HDC; nXStart, nYStart: integer; str: pchar; count: integer): bool;stdcall;<br> function NewTextOutW(theDC: HDC; nXStart, nYStart: integer; str: pWidechar; count: integer): bool; stdcall;<br> function NewExtTextOutA(theDC: HDC; nXStart, nYStart: integer; toOptions:Longint;<br> rect: PRect; Str: PAnsiChar; Count: Longint; Dx: PInteger): BOOL; stdcall;<br> function NewExtTextOutW(theDC: HDC; nXStart, nYStart: integer; toOptions:<br> Longint; rect: PRect;Str: Pwidechar; Count: Longint; Dx: PInteger): BOOL; stdcall;<br> function NewDrawTextA(theDC: HDC; lpString: PAnsiChar; nCount: Integer;<br> var lpRect: TRect; uFormat: UINT): Integer; stdcall;<br> function NewDrawTextW(theDC: HDC; lpString: PWideChar; nCount: Integer;<br> var lpRect: TRect; uFormat: UINT): Integer; stdcall; <br>implementation<br><br>var<br> MouseHook: THandle;<br> pShMem: PShareMem;<br> hMappingFile: THandle;<br> FirstProcess:boolean;{是否是第一个进程}<br> Hook: array[fBeginPaint..fDrawTextW] of THookClass;{API HOOK类}<br> i:integer;<br><br>{自定义的BeginPaint}<br>function NewBeginPaint(Wnd: HWND; var lpPaint: TPaintStruct): HDC; stdcall;<br>type<br> TBeginPaint=function (Wnd: HWND; var lpPaint: TPaintStruct): HDC; stdcall;<br>begin<br> Hook[fBeginPaint].Restore;<br> result:=TBeginPaint(Hook[fBeginPaint].OldFunction)(Wnd,lpPaint);<br> if Wnd=pshmem^.hHookWnd then{如果是当前鼠标的窗口句柄}<br> begin<br> pshmem^.DCMouse:=result;{记录它的返回值}<br> end<br> else pshmem^.DCMouse:=0;<br> Hook[fBeginPaint].Change;<br>end;<br><br>{自定义的GetWindowDC}<br>function NewGetWindowDC(Wnd: HWND): HDC; stdcall;<br>type<br> TGetWindowDC=function (Wnd: HWND): HDC; stdcall;<br>begin<br> Hook[fGetWindowDC].Restore;<br> result:=TGetWindowDC(Hook[fGetWindowDC].OldFunction)(Wnd);<br> if Wnd=pshmem^.hHookWnd then{如果是当前鼠标的窗口句柄}<br> begin<br> pshmem^.DCMouse:=result;{记录它的返回值}<br> end<br> else pshmem^.DCMouse:=0; <br> Hook[fGetWindowDC].Change;<br>end;<br><br>{自定义的GetDC}<br>function NewGetDC(Wnd: HWND): HDC; stdcall;<br>type<br> TGetDC=function (Wnd: HWND): HDC; stdcall;<br>begin<br> Hook[fGetDC].Restore;<br> result:=TGetDC(Hook[fGetDC].OldFunction)(Wnd);<br> if Wnd=pshmem^.hHookWnd then{如果是当前鼠标的窗口句柄}<br> begin<br> pshmem^.DCMouse:=result;{记录它的返回值}<br> end<br> else pshmem^.DCMouse:=0;<br> Hook[fGetDC].Change;<br>end;<br><br>{自定义的CreateCompatibleDC}<br>function NewCreateCompatibleDC(DC: HDC): HDC; stdcall;<br>type<br> TCreateCompatibleDC=function (DC: HDC): HDC; stdcall;<br>begin<br> Hook[fCreateCompatibleDC].Restore;<br> result:=TCreateCompatibleDC(Hook[fCreateCompatibleDC].OldFunction)(DC);<br> if DC=pshmem^.DCMouse then{如果是当前鼠标的窗口HDC}<br> begin<br> pshmem^.DCCompatible:=result;{记录它的返回值}<br> end<br> else pshmem^.DCCompatible:=0;<br> Hook[fCreateCompatibleDC].Change;<br>end;<br><br>function NewTextOutA(theDC: HDC; nXStart, nYStart: integer; str: pchar; count: integer): bool;<br> stdcall;<br>type<br> TTextOutA=function (theDC: HDC; nXStart, nYStart: integer; str: pchar; count: integer): bool;stdcall;<br>var<br> dwBytes: DWORD;<br> poOri, poDC, poText, poMouse: TPoint;<br> Size: TSize;<br> Rec:TRect;<br> faint:boolean;<br>begin<br> Hook[fTextOutA].Restore;{暂停截取API,恢复被截的函数}<br> try<br> if pShMem^.bCanSpyNow then{是否开始取词}<br> begin<br> GetDCOrgEx(theDC, poOri);{HDC的坐标}<br> poDC.x := nXStart;{显示的相对坐标}<br> poDC.y := nYStart;<br> if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}<br> begin<br> if (theDC=pShmem^.DCCompatible)then<br> faint:=false{精确匹配,就是指定的内存HDC}<br> else faint:=true;{模糊匹配,"可能"是内存HDC}<br> {取鼠标当前处的窗口(等效于Delphi的控件)坐标}<br> GetWindowRect(pShMem^.hHookWnd,Rec);<br> poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}<br> poOri.Y:=Rec.Top;<br> end<br> else begin{如果是普通HDC}<br> {局部逻辑坐标转化为设备相关坐标}<br> LPToDP(theDC, poDC, 1);<br> faint:=false;{精确匹配,是普通HDC}<br> end;<br> {计算显示文字的屏幕坐标}<br> poText.x := poDC.x + poOri.x;<br> poText.y := poDC.y + poOri.y;<br> {获取当前鼠标的坐标}<br> GetCursorPos(poMouse);<br> {如果对齐属性是居中}<br> if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then<br> begin<br> GetCurrentPositionEx(theDC, @poOri);<br> poText.x := poText.x + poOri.x;<br> poText.y := poText.y + poOri.y;<br> end;<br> {显示文字的长和宽}<br> GetTextExtentPoint(theDC, Str, Count, Size);<br> {鼠标是否在文本的范围内}<br> if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx)<br> and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy)<br> then<br> begin<br> {最多取MaxStringLen个字节}<br> dwBytes := min(Count, MaxStringLen);<br> {拷贝字符串}<br> CopyMemory(@(pShMem^.Text), Str, dwBytes);<br> {以空字符结束}<br> pShMem^.Text[dwBytes] := Chr(0);<br> {发送WM_MOUSEPT成功取词的消息给主程序}<br> postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fTextOutA, 2);<br> {如果输出的不是Tab键,而且是精确匹配的}<br> if (string(pShMem^.Text)<>#3)and(not faint) then<br> pShMem^.bCanSpyNow := False;{取词结束}<br> end;<br> end;<br> finally<br> {调用被截的函数}<br> result := TTextOutA(Hook[fTextOutA].OldFunction)(theDC, nXStart,<br> nYStart, str, count);<br> end;<br> Hook[fTextOutA].Change;{重新截取API}<br>end;<br><br><br>function NewTextOutW(theDC: HDC; nXStart, nYStart: integer; str: pWidechar; count: integer): bool; stdcall;<br>type<br> TTextOutW=function (theDC: HDC; nXStart, nYStart: integer; str: pWidechar; count: integer): bool; stdcall;<br>var<br> dwBytes: DWORD;<br> poOri, poDC, poText, poMouse: TPoint;<br> Size: TSize;<br> Rec:TRect;<br> faint:boolean;<br>begin<br> Hook[fTextOutW].Restore;{暂停截取API,恢复被截的函数}<br>// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));<br> try<br> if pShMem^.bCanSpyNow then{是否开始取词}<br> begin<br> GetDCOrgEx(theDC, poOri);{HDC的坐标}<br> poDC.x := nXStart;{显示的相对坐标}<br> poDC.y := nYStart;<br> if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}<br> begin<br> if (theDC=pShmem^.DCCompatible)then<br> faint:=false{精确匹配,就是指定的内存HDC}<br> else faint:=true;{模糊匹配,"可能"是内存HDC}<br> {取鼠标当前处的窗口(等效于Delphi的控件)坐标}<br> GetWindowRect(pShMem^.hHookWnd,Rec);<br> poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}<br> poOri.Y:=Rec.Top;<br> end<br> else begin{如果是普通HDC}<br> {局部逻辑坐标转化为设备相关坐标}<br> LPToDP(theDC, poDC, 1);<br> faint:=false;{精确匹配,是普通HDC}<br> end;<br> {计算显示文字的屏幕坐标}<br> poText.x := poDC.x + poOri.x;<br> poText.y := poDC.y + poOri.y;<br> {获取当前鼠标的坐标}<br> GetCursorPos(poMouse);<br> {如果对齐属性是居中}<br> if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then<br> begin<br> GetCurrentPositionEx(theDC, @poOri);<br> poText.x := poText.x + poOri.x;<br> poText.y := poText.y + poOri.y;<br> end;<br> {显示文字的长和宽}<br> GetTextExtentPointW(theDC, Str, Count, Size);<br> {鼠标是否在文本的范围内}<br> if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx)<br> and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy)<br> then<br> begin<br> {最多取MaxStringLen个字节}<br> dwBytes := min(Count*2, MaxStringLen);<br> {拷贝字符串}<br> CopyMemory(@(pShMem^.Text), Pchar(WideCharToString(Str)), dwBytes);<br> {以空字符结束}<br> pShMem^.Text[dwBytes] := Chr(0);<br> {发送WM_MOUSEPT成功取词的消息给主程序}<br> postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fTextOutW, 2);<br> {如果输出的不是Tab键,而且是精确匹配的}<br> if (string(pShMem^.Text)<>#3)and(not faint) then<br> pShMem^.bCanSpyNow := False;{取词结束}<br> end;<br> end;<br> finally<br> {调用被截的函数}<br> result := TTextOutW(Hook[fTextOutW].OldFunction)(theDC, nXStart, nYStart, str, Count);<br> end;<br> Hook[fTextOutW].Change;{重新截取API}<br>end;<br><br>function NewExtTextOutA(theDC: HDC; nXStart, nYStart: integer; toOptions:Longint;<br> rect: PRect; Str: PAnsiChar; Count: Longint; Dx: PInteger): BOOL; stdcall;<br>type<br> TExtTextOutA=function (theDC: HDC; nXStart, nYStart: integer; toOptions:Longint;<br> rect: PRect; Str: PAnsiChar; Count: Longint; Dx: PInteger): BOOL; stdcall;<br>var<br> dwBytes: DWORD;<br> poOri, poDC, poText, poMouse: TPoint;<br> Size: TSize;<br> Rec:TRect;<br> faint:boolean;<br>begin<br> Hook[fExtTextOutA].Restore;{暂停截取API,恢复被截的函数}<br>// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));<br> try<br> if pShMem^.bCanSpyNow then{是否开始取词}<br> begin<br> GetDCOrgEx(theDC, poOri);{HDC的坐标}<br> poDC.x := nXStart;{显示的相对坐标}<br> poDC.y := nYStart;<br> if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}<br> begin<br> if (theDC=pShmem^.DCCompatible)then<br> faint:=false{精确匹配,就是指定的内存HDC}<br> else faint:=true;{模糊匹配,"可能"是内存HDC}<br> {取鼠标当前处的窗口(等效于Delphi的控件)坐标}<br> GetWindowRect(pShMem^.hHookWnd,Rec);<br> poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}<br> poOri.Y:=Rec.Top;<br> end<br> else begin{如果是普通HDC}<br> {局部逻辑坐标转化为设备相关坐标}<br> LPToDP(theDC, poDC, 1);<br> faint:=false;{精确匹配,是普通HDC}<br> end;<br> {计算显示文字的屏幕坐标}<br> poText.x := poDC.x + poOri.x;<br> poText.y := poDC.y + poOri.y;<br> {获取当前鼠标的坐标}<br> GetCursorPos(poMouse);<br> {如果对齐属性是居中}<br> if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then<br> begin<br> GetCurrentPositionEx(theDC, @poOri);<br> poText.x := poText.x + poOri.x;<br> poText.y := poText.y + poOri.y;<br> end;<br> {显示文字的长和宽}<br> GetTextExtentPoint(theDC, Str, Count, Size);<br> {鼠标是否在文本的范围内}<br> if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx)<br> and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy)<br> then<br> begin<br> {最多取MaxStringLen个字节}<br> dwBytes := min(Count, MaxStringLen);<br> {拷贝字符串}<br> CopyMemory(@(pShMem^.Text), Str, dwBytes);<br> {以空字符结束}<br> pShMem^.Text[dwBytes] := Chr(0);<br> {发送WM_MOUSEPT成功取词的消息给主程序}<br> postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fExtTextOutA, 2);<br> {如果输出的不是Tab键,而且是精确匹配的}<br> if (string(pShMem^.Text)<>#3)and(not faint) then<br> pShMem^.bCanSpyNow := False;{取词结束}<br> end;<br> end;<br> finally<br> {调用被截的函数}<br> result := TExtTextOutA(Hook[fExtTextOutA].OldFunction)(theDC, nXStart, nYStart, toOptions, rect, Str,<br> Count, Dx);<br> end;<br> Hook[fExtTextOutA].Change;{重新截取API}<br>end;<br><br>function NewExtTextOutW(theDC: HDC; nXStart, nYStart: integer; toOptions:<br> Longint; rect: PRect;<br> Str: Pwidechar; Count: Longint; Dx: PInteger): BOOL; stdcall;<br>type<br> TExtTextOutW=function (theDC: HDC; nXStart, nYStart: integer; toOptions:Longint;<br> rect: PRect; Str: Pwidechar; Count: Longint; Dx: PInteger): BOOL; stdcall;<br>var<br> dwBytes: DWORD;<br> poOri, poDC, poText, poMouse: TPoint;<br> Size: TSize;<br> Rec:TRect;<br> faint:boolean; <br>begin<br> Hook[fExtTextOutW].Restore;{暂停截取API,恢复被截的函数}<br>// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));<br> try<br> if pShMem^.bCanSpyNow then{是否开始取词}<br> begin<br> GetDCOrgEx(theDC, poOri);{HDC的坐标}<br> poDC.x := nXStart;{显示的相对坐标}<br> poDC.y := nYStart;<br> if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}<br> begin<br> if (theDC=pShmem^.DCCompatible)then<br> faint:=false{精确匹配,就是指定的内存HDC}<br> else faint:=true;{模糊匹配,"可能"是内存HDC}<br> {取鼠标当前处的窗口(等效于Delphi的控件)坐标}<br> GetWindowRect(pShMem^.hHookWnd,Rec);<br> poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}<br> poOri.Y:=Rec.Top;<br> end<br> else begin{如果是普通HDC}<br> {局部逻辑坐标转化为设备相关坐标}<br> LPToDP(theDC, poDC, 1);<br> faint:=false;{精确匹配,是普通HDC}<br> end;<br> {计算显示文字的屏幕坐标}<br> poText.x := poDC.x + poOri.x;<br> poText.y := poDC.y + poOri.y;<br> {获取当前鼠标的坐标}<br> GetCursorPos(poMouse);<br> {如果对齐属性是居中}<br> if (GetTextAlign(theDC) and TA_UPDATECP) <> 0 then<br> begin<br> GetCurrentPositionEx(theDC, @poOri);<br> poText.x := poText.x + poOri.x;<br> poText.y := poText.y + poOri.y;<br> end;<br> {显示文字的长和宽}<br> GetTextExtentPointW(theDC, Str, Count, Size);<br> {鼠标是否在文本的范围内}<br> if (poMouse.x >= poText.x) and (poMouse.x <= poText.x + Size.cx)<br> and (poMouse.y >= poText.y) and (poMouse.y <= poText.y + Size.cy)<br> then<br> begin<br> {最多取MaxStringLen个字节}<br> dwBytes := min(Count*2, MaxStringLen);<br> {拷贝字符串}<br> CopyMemory(@(pShMem^.Text), Pchar(WideCharToString(Str)), dwBytes);<br> {以空字符结束}<br> pShMem^.Text[dwBytes] := Chr(0);<br> {发送WM_MOUSEPT成功取词的消息给主程序}<br> postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fExtTextOutW, 2);<br> {如果输出的不是Tab键,而且是精确匹配的}<br> if (string(pShMem^.Text)<>#3)and(not faint) then<br> pShMem^.bCanSpyNow := False;{取词结束}<br> end;<br> end;<br> finally<br> {调用被截的函数}<br> result := TExtTextOutW(Hook[fExtTextOutW].OldFunction)(theDC, nXStart, nYStart, toOptions,Rect, Str, Count, Dx);<br> end;<br> Hook[fExtTextOutW].Change;{重新截取API}<br>end;<br><br>function NewDrawTextA(theDC: HDC; lpString: PAnsiChar; nCount: Integer;<br> var lpRect: TRect; uFormat: UINT): Integer; stdcall;<br>type<br> TDrawTextA=function (theDC: HDC; lpString: PAnsiChar; nCount: Integer;<br> var lpRect: TRect; uFormat: UINT): Integer; stdcall;<br>var<br> poMouse,poOri,poDC: TPoint;<br> dwBytes: integer;<br> RectSave,rec:TRect;<br> faint:boolean; <br>begin<br> Hook[fDrawTextA].Restore;{暂停截取API,恢复被截的函数}<br>// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));<br> try<br> if pShMem^.bCanSpyNow then{是否开始取词}<br> begin<br> GetDCOrgEx(theDC, poOri);{HDC的坐标}<br> poDC.x := 0;{局部逻辑坐标初始化为(0,0)}<br> poDC.y := 0;<br> if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}<br> begin<br> if (theDC=pShmem^.DCCompatible)then<br> faint:=false{精确匹配,就是指定的内存HDC}<br> else faint:=true;{模糊匹配,"可能"是内存HDC}<br> {取鼠标当前处的窗口(等效于Delphi的控件)坐标}<br> GetWindowRect(pShMem^.hHookWnd,Rec);<br> poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}<br> poOri.Y:=Rec.Top;<br> end<br> else begin{如果是普通HDC}<br> {局部逻辑坐标转化为设备相关坐标}<br> LPToDP(theDC, poDC, 1);<br> faint:=false;{精确匹配,是普通HDC}<br> end;<br> RectSave := lpRect;{显示的矩形}<br> OffsetRect(RectSave, poOri.x+poDC.x, poOri.y+poDC.y);{显示的矩形加上偏移}<br> {获取当前鼠标的坐标}<br> GetCursorPos(poMouse);<br> {鼠标是否在文本的范围内}<br> if PtInRect(RectSave, poMouse) then<br> begin<br> if nCount=-1 then<br> begin<br> strcopy(@(pShMem^.Text[0]), lpString);<br> end<br> else begin<br> {最多取MaxStringLen个字节}<br> dwBytes := min(nCount, MaxStringLen);<br> {拷贝字符串}<br> CopyMemory(@(pShMem^.Text[0]), lpString, dwBytes);<br> {以空字符结束}<br> pShMem^.Text[dwBytes] := Chr(0);<br> end;<br> {发送WM_MOUSEPT成功取词的消息给主程序}<br> postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextA, 2);<br> {如果输出的不是Tab键,而且是精确匹配的}<br> if (string(pShMem^.Text)<>#3)and(not faint) then<br> pShMem^.bCanSpyNow := False;{取词结束}<br> end;<br> end;<br> finally<br> {调用被截的函数}<br> result := TDrawTextA(Hook[fDrawTextA].OldFunction)(theDC, lpString, nCount, lpRect, uFormat);<br> end;<br> Hook[fDrawTextA].Change;{重新截取API}<br>end;<br><br>function NewDrawTextW(theDC: HDC; lpString: PWideChar; nCount: Integer;<br> var lpRect: TRect; uFormat: UINT): Integer; stdcall;<br>type<br> TDrawTextW=function (theDC: HDC; lpString: PWideChar; nCount: Integer;<br> var lpRect: TRect; uFormat: UINT): Integer; stdcall;<br>var<br> poMouse,poOri,poDC: TPoint;<br> dwBytes: integer;<br> RectSave,rec:TRect;<br> faint:boolean;<br>begin<br> Hook[fDrawTextW].Restore;{暂停截取API,恢复被截的函数}<br>// SetTextColor(thedc,RGB(COLOR1,COLOR2,COLOR3));<br> try<br> if pShMem^.bCanSpyNow then{是否开始取词}<br> begin<br> GetDCOrgEx(theDC, poOri);{HDC的坐标}<br> poDC.x := 0;{局部逻辑坐标初始化为(0,0)}<br> poDC.y := 0;<br> if(poOri.X=0)and(poOri.Y=0)then{如果HDC的坐标为(0,0)}<br> begin<br> if (theDC=pShmem^.DCCompatible)then<br> faint:=false{精确匹配,就是指定的内存HDC}<br> else faint:=true;{模糊匹配,"可能"是内存HDC}<br> {取鼠标当前处的窗口(等效于Delphi的控件)坐标}<br> GetWindowRect(pShMem^.hHookWnd,Rec);<br> poOri.X:=Rec.Left;{把窗口坐标作为HDC的坐标}<br> poOri.Y:=Rec.Top;<br> end<br> else begin{如果是普通HDC}<br> {局部逻辑坐标转化为设备相关坐标}<br> LPToDP(theDC, poDC, 1);<br> faint:=false;{精确匹配,是普通HDC}<br> end;<br> RectSave := lpRect;{显示的矩形}<br> OffsetRect(RectSave, poOri.x+poDC.x, poOri.y+poDC.y);{显示的矩形加上偏移}<br> {获取当前鼠标的坐标}<br> GetCursorPos(poMouse);<br> {鼠标是否在文本的范围内}<br> if PtInRect(RectSave, poMouse) then<br> begin<br> if nCount=-1 then<br> begin<br> strcopy(@(pShMem^.Text[0]), Pchar(WideCharToString(lpString)));<br> end<br> else begin<br> {最多取MaxStringLen个字节}<br> dwBytes := min(nCount*2, MaxStringLen);<br> {拷贝字符串}<br> CopyMemory(@(pShMem^.Text[0]), Pchar(WideCharToString(lpString)), dwBytes);<br> {以空字符结束}<br> pShMem^.Text[dwBytes] := Chr(0);<br> end;<br> {发送WM_MOUSEPT成功取词的消息给主程序}<br> postMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextW, 2);<br> {如果输出的不是Tab键,而且是精确匹配的}<br> if (string(pShMem^.Text)<>#3)and(not faint) then<br> pShMem^.bCanSpyNow := False;{取词结束}<br> end;<br> end;<br> finally<br> {调用被截的函数}<br> result := TDrawTextW(Hook[fDrawTextW].OldFunction)(theDC, lpString, nCount, lpRect, uFormat);<br> end;<br> Hook[fDrawTextW].Change;{重新截取API}<br>end;<br><br>{遍历所有菜单项}<br>procedure IterateThroughItems(WND:HWND;menu:Hmenu;p:TPoint;Level:integer);<br>var<br> i:integer;<br> info:TMenuItemInfo;<br> rec:TRect;<br>begin<br> for i:=0 to GetMenuItemCount(menu)-1 do {遍历所有子菜单项}<br> begin<br> fillchar(info,sizeof(info),0);<br> info.cbSize:=sizeof(info);<br> info.fMask:=MIIM_TYPE or MIIM_SUBMENU;<br> info.cch:=256;<br> getmem(info.dwTypeData,256);<br> {取菜单的文字}<br> GetMenuItemInfo(menu,i,true,info);<br> {取菜单的坐标}<br> GetMenuItemRect(wnd,menu,i,rec);<br> {如果鼠标在菜单的矩形区域内}<br> if (rec.Left<=p.X)and(p.X<=rec.Right)and(rec.Top<=p.Y)and(p.Y<=rec.Bottom)then<br> if (info.cch<>0) then<br> begin<br> {取出菜单文字}<br> strlcopy(pShMem^.Text,info.dwTypeData,min(info.cch,MaxStringLen));<br> pShMem^.bCanSpyNow := False;<br> {发送WM_MOUSEPT成功取词的消息给主程序}<br> PostMessage(pShMem^.hProcWnd, WM_MOUSEPT, fDrawTextW, 2);<br> end;<br>// freemem(info.dwTypeData,256);<br>// info.dwTypeData:=nil;<br> if info.hSubMenu<>0 then {如果它有下级子菜单,则归递调用}<br> begin<br> IterateThroughItems(wnd,info.hSubMenu,p,Level+1);<br> end;<br> end;<br>end;<br><br>{定时器,每10毫秒被调用一次}<br>procedure fOnTimer(theWnd: HWND; msg, idTimer: Cardinal; dwTime: DWORD); stdcall;<br>var<br> InvalidRect: TRECT;<br> buffer:array[0..256]of char;<br> menu:Hmenu;<br> MousePoint:TPoint;<br>begin<br> pShMem^.nTimePassed := pShMem^.nTimePassed + 1;<br> if pShMem^.nTimePassed = 10 then {如果鼠标停留了0.1秒}<br> begin<br> MousePoint:=pshmem^.pMouse;<br> {获取当前鼠标所在的窗口(等效于Delphi的控件)句柄}<br> pshmem^.hHookWnd := WindowFromPoint(MousePoint);<br> {屏幕坐标转换为窗口(等效于Delphi的控件)客户区的坐标}<br> ScreenToClient(pshmem^.hHookWnd, MousePoint);<br> pShMem^.bCanSpyNow := true;{可以开始取词}<br> {如果客户区的坐标为负值,则说明鼠标位于菜单或标题的上空}<br> if(MousePoint.x<0)or(MousePoint.y<0) then<br> begin<br> {读取并设置标题,让其重绘}<br> Getwindowtext(pshmem^.hHookWnd,buffer,sizeof(buffer)-1);<br> Setwindowtext(pshmem^.hHookWnd,pchar(string(buffer)+' '));<br> Setwindowtext(pshmem^.hHookWnd,buffer);<br> {客户区的坐标恢复为屏幕坐标}<br> ClientToScreen(pshmem^.hHookWnd, MousePoint);<br> {取出当前的菜单}<br> menu:=GetMenu(pshmem^.hHookWnd);<br> if menu<>0 then<br> {遍历所有菜单,判断是否位于鼠标的下方}<br> IterateThroughItems(pshmem^.hHookWnd,menu,MousePoint,1);<br> end<br> else begin{否则,说明鼠标位于客户区}<br> InvalidRect.left := MousePoint.x;<br> InvalidRect.top := MousePoint.y;<br> InvalidRect.Right := MousePoint.x + 1;<br> InvalidRect.Bottom := MousePoint.y + 1;<br> {重绘客户区}<br> InvalidateRect(pshmem^.hHookWnd, @InvalidRect, false);<br> end;<br> end<br> else if pShMem^.nTimePassed >= 11 then<br> begin<br> pShMem^.nTimePassed := 11;<br> end;<br> {清空pShmem}<br>end;<br><br>{鼠标钩子}<br>function MouseHookProc(nCode: integer; wPar: WParam; lPar: LParam): lResult;<br> stdcall;<br>var<br> pMouseInf: TMouseHookStruct;<br>begin<br> pShMem^.nTimePassed := 0;<br> if (nCode >= 0) and ((wPar = WM_MOUSEMOVE)or(wPar = WM_NCMOUSEMOVE)) then<br> begin<br> pMouseInf := (PMouseHookStruct(lPar))^;<br> if (pShMem^.pMouse.x <> pMouseInf.pt.x) or<br> (pShMem^.pMouse.y <> pMouseInf.pt.y) then<br> begin<br> if nCode = HC_NOREMOVE then<br> pShMem^.fStrMouseQueue := 'Not removed from the queue'<br> else<br> pShMem^.fStrMouseQueue := 'Removed from the queue';<br> {鼠标的坐标}<br> pShMem^.pMouse := pMouseInf.pt;<br> {鼠标所在的窗口}<br> pShMem^.hHookWnd := pMouseInf.hwnd;<br> {1是自定义的数值,表明这是鼠标消息}<br> postMessage(pShMem^.hProcWnd, WM_MOUSEPT, 1, 1);<br> end;<br> end;<br> Result := CallNextHookEx(MouseHook, nCode, wPar, lPar);<br>end;<br><br>{开始取词}<br>procedure StartHook; stdcall;<br>begin<br> if MouseHook=0 then<br> begin<br> pShMem^.fTimerID := SetTimer(0, 0, 10, @fOnTimer);<br> {注入其它进程}<br> MouseHook := SetWindowsHookEx(WH_MOUSE, MouseHookProc, HInstance, 0);<br> end;<br>end;<br><br>{停止取词}<br>procedure StopHook; stdcall;<br>begin<br> if MouseHook<>0 then<br> begin<br> KillTimer(0, pShMem^.fTimerID);<br> UnhookWindowsHookEx(MouseHook);<br> MouseHook:=0;<br> end;<br>end;<br><br>initialization<br> hMappingFile := OpenFileMapping(FILE_MAP_WRITE,False,MappingFileName);<br> if hMappingFile=0 then<br> begin<br> hMappingFile := CreateFileMapping($FFFFFFFF,nil,PAGE_READWRITE,0,SizeOf(TShareMem),MappingFileName);<br> FirstProcess:=true; {这是第一个进程,即主程序}<br> end<br> else FirstProcess:=false;<br> if hMappingFile=0 then Exception.Create('不能建立共享内存!');<br><br> pShMem := MapViewOfFile(hMappingFile,FILE_MAP_WRITE or FILE_MAP_READ,0,0,0);<br> if pShMem = nil then<br> begin<br> CloseHandle(hMappingFile);<br> Exception.Create('不能映射共享内存!');<br> end;<br> if FirstProcess then<br> begin<br> pShMem^.bCanSpyNow:=false;<br> end;<br> Hook[fBeginPaint]:=THookClass.Create(Trap,@BeginPaint,@NewBeginPaint);{Trap=True陷阱式}<br> Hook[fGetWindowDC]:=THookClass.Create(Trap,@GetWindowDC,@NewGetWindowDC);<br> Hook[fGetDC]:=THookClass.Create(Trap,@GetDC,@NewGetDC);<br> Hook[fCreateCompatibleDC]:=THookClass.Create(Trap,@CreateCompatibleDC,@NewCreateCompatibleDC);<br> Hook[fTextOutA]:=THookClass.Create(Trap,@TextOutA,@NewTextOutA);<br> Hook[fTextOutW]:=THookClass.Create(Trap,@TextOutW,@NewTextOutW);<br> Hook[fExtTextOutA]:=THookClass.Create(Trap,@ExtTextOutA,@NewExtTextOutA);<br> Hook[fExtTextOutW]:=THookClass.Create(Trap,@ExtTextOutW,@NewExtTextOutW);<br> Hook[fDrawTextA]:=THookClass.Create(Trap,@DrawTextA,@NewDrawTextA);<br> Hook[fDrawTextW]:=THookClass.Create(Trap,@DrawTextW,@NewDrawTextW); <br>finalization<br> for i:=Low(hook) to High(hook) do<br> if Hook
<>nil then<br> Hook.Destroy;<br> UnMapViewOfFile(pShMem); {取消映射视图}<br> CloseHandle(hMappingFile); {关闭映射文件句柄}<br>end.<br><br><br>unit UnitHookType;<br><br>interface<br><br>uses windows, messages;<br><br>const<br> MaxStringLen = 100;<br> WM_MOUSEPT = WM_USER + 1138;<br> MappingFileName = 'GetWord32 for 9x NT 2000';<br> fBeginPaint=0;<br> fGetWindowDC=1;<br> fGetDC=2;<br> fCreateCompatibleDC=3;<br> fTextOutA=4;<br> fTextOutW=5;<br> fExtTextOutA=6;<br> fExtTextOutW=7;<br> fDrawTextA=8;<br> fDrawTextW=9;<br>type<br> PPointer = ^Pointer;<br> TShareMem = packed record<br> hProcWnd: HWND; {主应用窗口句柄}<br> hHookWnd: HWND; {鼠标所在窗口}<br> pMouse: TPoint; {鼠标信息}<br> DCMouse,DCCompatible: HDC;<br> fTimerID: integer;<br> fStrMouseQueue: array[0..MaxStringLen] of Char; {鼠标信息串}<br> nTimePassed: integer; {鼠标停留的时间}<br> bCanSpyNow: Boolean; {开始取词}<br> Text: array[0..MaxStringLen] of Char; {字符串}<br> end;<br> PShareMem = ^TShareMem;<br><br>implementation<br><br>end.<br><br><br>unit UnitNt2000Hook;<br><br>interface<br><br>uses classes, Windows,SysUtils, messages,dialogs;<br><br>type<br> TImportCode = packed record<br> JumpInstruction: Word;<br> AddressOfPointerToFunction: PPointer;<br> end;<br> PImportCode = ^TImportCode;<br> PImage_Import_Entry = ^Image_Import_Entry;<br> Image_Import_Entry = record<br> Characteristics: DWORD;<br> TimeDateStamp: DWORD;<br> MajorVersion: Word;<br> MinorVersion: Word;<br> Name: DWORD;<br> LookupTable: DWORD;<br> end;<br> TLongJmp = packed record<br> JmpCode: ShortInt; {指令,用$E9来代替系统的指令}<br> FuncAddr: DWORD; {函数地址}<br> end;<br><br> THookClass = class<br> private<br> Trap:boolean; {调用方式:True陷阱式,False改引入表式}<br> hProcess: Cardinal; {进程句柄,只用于陷阱式}<br> AlreadyHook:boolean; {是否已安装Hook,只用于陷阱式}<br> AllowChange:boolean; {是否允许安装、卸载Hook,只用于改引入表式}<br> Oldcode: array[0..4]of byte; {系统函数原来的前5个字节}<br> Newcode: TLongJmp; {将要写在系统函数的前5个字节}<br> private<br> public<br> OldFunction,NewFunctionointer;{被截函数、自定义函数}<br> constructor Create(IsTrap:boolean;OldFun,NewFunointer);<br> constructor Destroy;<br> procedure Restore;<br> procedure Change;<br> published<br> end;<br><br>implementation<br><br>{取函数的实际地址。如果函数的第一个指令是Jmp,则取出它的跳转地址(实际地址),这往往是由于程序中含有Debug调试信息引起的}<br>function FinalFunctionAddress(Code: Pointer): Pointer;<br>Var<br> func: PImportCode;<br>begin<br> Result:=Code;<br> if Code=nil then exit;<br> try<br> func:=code;<br> if (func.JumpInstruction=$25FF) then<br> {指令二进制码FF 25 汇编指令jmp [...]}<br> Func:=func.AddressOfPointerToFunction^;<br> result:=Func;<br> except<br> Result:=nil;<br> end;<br>end;<br><br>{更改引入表中指定函数的地址,只用于改引入表式}<br>function PatchAddressInModule(BeenDone:Tlist;hModule: THandle; OldFunc,NewFunc: Pointer):integer;<br>const<br> SIZE=4;<br>Var<br> Dos: PImageDosHeader;<br> NT: PImageNTHeaders;<br> ImportDesc: PImage_Import_Entry;<br> rva: DWORD;<br> Func: PPointer;<br> DLL: String;<br> f: Pointer;<br> written: DWORD;<br> mbi_thunk:TMemoryBasicInformation;<br> dwOldProtectWORD;<br>begin<br> Result:=0;<br> if hModule=0 then exit;<br> Dos:=Pointer(hModule);<br> {如果这个DLL模块已经处理过,则退出。BeenDone包含已处理的DLL模块}<br> if BeenDone.IndexOf(Dos)>=0 then exit;<br> BeenDone.Add(Dos);{把DLL模块名加入BeenDone}<br> OldFunc:=FinalFunctionAddress(OldFunc);{取函数的实际地址}<br><br> {如果这个DLL模块的地址不能访问,则退出}<br> if IsBadReadPtr(Dos,SizeOf(TImageDosHeader)) then exit;<br> {如果这个模块不是以'MZ'开头,表明不是DLL,则退出}<br> if Dos.e_magic<>IMAGE_DOS_SIGNATURE then exit;{IMAGE_DOS_SIGNATURE='MZ'}<br><br> {定位至NT Header}<br> NT :=Pointer(Integer(Dos) + dos._lfanew);<br> {定位至引入函数表}<br> RVA:=NT^.OptionalHeader.<br> DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;<br> if RVA=0 then exit;{如果引入函数表为空,则退出}<br> {把函数引入表的相对地址RVA转换为绝对地址}<br> ImportDesc := pointer(DWORD(Dos)+RVA);{Dos是此DLL模块的首地址}<br><br> {遍历所有被引入的下级DLL模块}<br> While (ImportDesc^.Name<>0) do<br> begin<br> {被引入的下级DLL模块名字}<br> DLL:=PChar(DWORD(Dos)+ImportDesc^.Name);<br> {把被导入的下级DLL模块当做当前模块,进行递归调用}<br> PatchAddressInModule(BeenDone,GetModuleHandle(PChar(DLL)),OldFunc,NewFunc);<br><br> {定位至被引入的下级DLL模块的函数表}<br> Func:=Pointer(DWORD(DOS)+ImportDesc.LookupTable);<br> {遍历被引入的下级DLL模块的所有函数}<br> While Func^<>nil do<br> begin<br> f:=FinalFunctionAddress(Func^);{取实际地址}<br> if f=OldFunc then {如果函数实际地址就是所要找的地址}<br> begin<br> VirtualQuery(Func,mbi_thunk, sizeof(TMemoryBasicInformation));<br> VirtualProtect(Func,SIZE,PAGE_EXECUTE_WRITECOPY,mbi_thunk.Protect);{更改内存属性}<br> WriteProcessMemory(GetCurrentProcess,Func,@NewFunc,SIZE,written);{把新函数地址覆盖它}<br> VirtualProtect(Func, SIZE, mbi_thunk.Protect,dwOldProtect);{恢复内存属性}<br> end;<br> If Written=4 then Inc(Result);<br>// else showmessagefmt('error:%d',[Written]);<br> Inc(Func);{下一个功能函数}<br> end;<br> Inc(ImportDesc);{下一个被引入的下级DLL模块}<br> end;<br>end;<br><br>{HOOK的入口,其中IsTrap表示是否采用陷阱式}<br>constructor THookClass.Create(IsTrap:boolean;OldFun,NewFunointer);<br>begin<br> {求被截函数、自定义函数的实际地址}<br> OldFunction:=FinalFunctionAddress(OldFun);<br> NewFunction:=FinalFunctionAddress(NewFun);<br><br> Trap:=IsTrap;<br> if Trap then{如果是陷阱式}<br> begin<br> {以特权的方式来打开当前进程}<br> hProcess := OpenProcess(PROCESS_ALL_ACCESS,FALSE, GetCurrentProcessID);<br> {生成jmp xxxx的代码,共5字节}<br> Newcode.JmpCode := ShortInt($E9); {jmp指令的十六进制代码是E9}<br> NewCode.FuncAddr := DWORD(NewFunction) - DWORD(OldFunction) - 5;<br> {保存被截函数的前5个字节}<br> move(OldFunction^,OldCode,5);<br> {设置为还没有开始HOOK}<br> AlreadyHook:=false;<br> end;<br> {如果是改引入表式,将允许HOOK}<br> if not Trap then AllowChange:=true;<br> Change; {开始HOOK}<br> {如果是改引入表式,将暂时不允许HOOK}<br> if not Trap then AllowChange:=false;<br>end;<br><br>{HOOK的出口}<br>constructor THookClass.Destroy;<br>begin<br> {如果是改引入表式,将允许HOOK}<br> if not Trap then AllowChange:=true;<br> Restore; {停止HOOK}<br> if Trap then{如果是陷阱式}<br> CloseHandle(hProcess);<br>end;<br><br>{开始HOOK}<br>procedure THookClass.Change;<br>var<br> nCount: DWORD;<br> BeenDone: TList;<br>begin<br> if Trap then{如果是陷阱式}<br> begin<br> if (AlreadyHook)or (hProcess = 0) or (OldFunction = nil) or (NewFunction = nil) then<br> exit;<br> AlreadyHook:=true;{表示已经HOOK}<br> WriteProcessMemory(hProcess, OldFunction, @(Newcode), 5, nCount);<br> end<br> else begin{如果是改引入表式}<br> if (not AllowChange)or(OldFunction=nil)or(NewFunction=nil)then exit;<br> BeenDone:=TList.Create; {用于存放当前进程所有DLL模块的名字}<br> try<br> PatchAddressInModule(BeenDone,GetModuleHandle(nil),OldFunction,NewFunction);<br> finally<br> BeenDone.Free;<br> end;<br> end;<br>end;<br><br>{恢复系统函数的调用}<br>procedure THookClass.Restore;<br>var<br> nCount: DWORD;<br> BeenDone: TList;<br>begin<br> if Trap then{如果是陷阱式}<br> begin<br> if (not AlreadyHook) or (hProcess = 0) or (OldFunction = nil) or (NewFunction = nil) then<br> exit;<br> WriteProcessMemory(hProcess, OldFunction, @(Oldcode), 5, nCount);<br> AlreadyHook:=false;{表示退出HOOK}<br> end<br> else begin{如果是改引入表式}<br> if (not AllowChange)or(OldFunction=nil)or(NewFunction=nil)then exit;<br> BeenDone:=TList.Create;{用于存放当前进程所有DLL模块的名字}<br> try<br> PatchAddressInModule(BeenDone,GetModuleHandle(nil),NewFunction,OldFunction);<br> finally<br> BeenDone.Free;<br> end;<br> end;<br>end;<br><br>end.