APIHOOK

  • 主题发起人 主题发起人 import
  • 开始时间 开始时间
I

import

Unregistered / Unconfirmed
GUEST, unregistred user!
tseug, 时间:2001-5-23 15:20:39, ID:539139
参考下面的吧
 
数据定义单元
unit DefUnit;
interface
uses
Messages, Windows;
const
WM_GETWORD = WM_USER + Ord('Y') + Ord('y') + Ord('g') + Ord('w');
csMappingFileName = 'Mapping File By Yygw'; //内存映象名
csMaxStringLen = 64; //最大字符串长度
csCodeSize = 4096; //加载到内存映象视图的代码长度
csJmpCode = $E9; //跳转指令机器码
csGdiName = 'GDI32'; //GDI32.DLL
csApiFunName = 'ExtTextOutA'; //函数名
csUserName = 'HOOK_DLL'; //用户DLL名
csUserFunName = 'MyExtTextOutA'; //用户函数名
type
TIDT = array [0..5] of Byte; //IDT表
TLongJump = packed record //跳转指令
JmpOp: Byte; //操作码
Addr: Pointer; //地址
end;
PShareMem = ^TShareMem;
TShareMem = packed record
//以下参数面向主程序
hProcWnd: HWND; //应用程序主窗口
hHookWnd: HWND; //当前挂钩窗口
hProc: THandle; //应用程序进程ID
pMouse: TPoint; //鼠标位置
HookDelay: Cardinal; //取词延时(ms)
Enabled: Boolean; //允许取词
lpText: array[0..csMaxStringLen] of Char; //当前取到的词
TextRect: TRect; //当前文本框
 
//以下参数内部使用
lpOldExtTextOutA: Pointer; //旧函数入口
lpNewExtTextOutA: Pointer; //自定义函数入口
lpRing0_WriteMemory: Pointer; //挂接函数入口
lpOldRing0_WriteMemory: Pointer; //旧代码入口
AllowTake: Boolean; //可以取词
OldCode: TLongJump; //旧函数代码
NewCode: TLongJump; //跳转代码
lpSour, lpDes: Pointer; //内存复制地址
lpOldGate: DWord; //旧中断门入口
IDT: TIDT; //IDT数据
Code: array [0..csCodeSize - 1] of Byte; //代码区
end;
const
SizeOfLongJump = SizeOf(TLongJump);
var
pShMem: pShareMem; //指向一块>2G的共享地址
implementation
end.
//Api挂接单元,需调试
unit ApiHook;
interface
uses
Messages, Windows;
function InitApiHook: Boolean; //初始化挂接
function InstallApi: Boolean; //挂接ExtTextOutA
function UnInstallApi: Boolean; //卸去挂接
function CloseApiHook: Boolean; //关闭挂接
implementation
uses
DefUnit;
 
var
pHookMem: PShareMem; //伪指针,实际代码中被替换为pShMem
hMappingFile: THandle; //映象文件句柄
Inited: Boolean; //已初始化
Hooked: Boolean; //已挂接
const
csExceptionUsed = 5; //中断号
//跳到Ring0修改内存的过程
//源地址和目标地址放在pShMem^.lpSour和lpDes中
//实际代码被加载到pShMem^.Code中可由所有进程共享调用运行
//内部的pHookMem被替换为pShMem的值
procedure Ring0_WriteMemory;
asm
PUSHA //保存现场
LEA EAX, pHookMem
SIDT TShareMem([EAX]).IDT //获取 IDT
MOV EBX, DWORD PTR [TShareMem([EAX]).IDT + 2]
ADD EBX, 8 * csExceptionUsed //Ebx -> IDT 中 csExceptionUsed 中断入口
CLI //清中断
MOV DX, WORD PTR [EBX + 6] //保存中断门高字
SHL EDX, 16
MOV DX, WORD PTR [EBX] //低字
MOV DWORD PTR [TShareMem([EAX]).lpOldGate], EDX
 
//计算实际运行的代码和原代码的地址差
MOV ECX, DWORD PTR [TShareMem([EAX]).lpRing0_WriteMemory]
SUB ECX, DWORD PTR [TShareMem([EAX]).lpOldRing0_WriteMemory]
LEA EAX, @Ring0Code //"安装挂钩" - 用户中断门
ADD EAX, ECX //获得运行代码的@Ring0Code地址
MOV WORD PTR [EBX], AX //低字
SHR EAX, 16
MOV WORD PTR [EBX + 6], AX //高字
DB $CD, csExceptionUsed //INT csExceptionUsed 的机器码
//触发中断跳到Ring0代码
LEA EAX, pHookMem
MOV EBX, DWORD PTR [TShareMem([EAX]).IDT + 2] //恢复中断门
ADD EBX, 8 * csExceptionUsed
MOV EDX, DWORD PTR [TShareMem([EAX]).lpOldGate]
MOV WORD PTR [EBX], DX
SHR EDX, 16
MOV WORD PTR [EBX +6], DX
JMP @Exit
@Ring0Code: //运行在Ring0下的代码
CLI
LEA EAX, pHookMem
MOV EBX, TShareMem[EAX].lpSour //源地址
MOV EDX, TShareMem[EAX].lpDes //目标地址
MOV ECX, SizeOfLongJump
@Loop:
MOV AL, [EBX] //内存复制
MOV [EDX], AL
INC EBX
INC EDX
LOOP @Loop
IRETD //返回到Ring3
@Exit:
POPA //恢复现场
end;
//用户的ExtTextOutA函数
//实际代码被加载到pShMem^.Code中可由所有进程共享调用运行
//内部的pHookMem被替换为pShMem的值
procedure MyExtTextOutA;
asm
PUSH EBP
MOV EBP, ESP
//以下代码用SoftICE跟踪调试时正常
//但实际使用时在窗口最小化或鼠标指向快速启动栏时死机
{PUSH EBX
PUSH ECX
PUSH EDX
PUSH ESI
PUSH EDI
//恢复原ExtTextOutA代码
LEA EAX, pHookMem
LEA EBX, TShareMem([EAX]).OldCode //旧函数代码
MOV TShareMem([EAX]).lpSour, EBX
MOV EBX, TShareMem([EAX]).lpOldExtTextOutA //旧函数入口
MOV TShareMem([EAX]).lpDes, EBX
MOV EBX, TShareMem([EAX]).lpRing0_WriteMemory
CALL EBX //调用Ring0_WriteMemory恢复原函数代码
//调用原ExtTextOutA
MOV EAX, [EBP + $24] //lpDx
PUSH EAX
MOV EAX, [EBP + $20] //cbCount
PUSH EAX
MOV EAX, [EBP + $1C] //lpString
PUSH EAX
MOV EAX, [EBP + $18] //lprc
PUSH EAX
MOV EAX, [EBP + $14] //fuOptions
PUSH EAX
MOV EAX, [EBP + $10] //Y
PUSH EAX
MOV EAX, [EBP + $0C] //X
PUSH EAX
MOV EAX, [EBP + $08] //hdc
PUSH EAX
LEA EAX, pHookMem
MOV EBX, TShareMem([EAX]).lpOldExtTextOutA
CALL EBX
PUSH EAX //返回结果
//重新挂接ExtTextOutA
LEA EAX, pHookMem
LEA EBX, TShareMem([EAX]).NewCode //跳转指令
MOV TShareMem([EAX]).lpSour, EBX
MOV EBX, TShareMem([EAX]).lpOldExtTextOutA //原函数入口
MOV TShareMem([EAX]).lpDes, EBX
MOV EBX, TShareMem([EAX]).lpRing0_WriteMemory
CALL EBX //调用Ring0_WriteMemory重新挂接
POP EAX
POP EDI
POP ESI
POP EDX
POP ECX
POP EBX}
MOV EAX, False //调试时用,返回假
@Exit:
POP EBP //返回
RET $20
end;
//安装Api挂钩
function InstallApi: Boolean;
var
pHookCode: Pointer; //要加载到pShMem^.Code中的代码入口
CodeSize: Integer; //实际代码长度
pInt: PInteger; //指向一个32位整数
i: Integer;
Ring0Fun: Pointer; //实际的Ring0_WriteMemory入口
begin
Result := False;
if Hooked or not Inited then
Exit; //已挂接过或未初始化
Hooked := False;
pShMem^.lpOldExtTextOutA := GetProcAddress(GetModuleHandle(csGdiName),
csApiFunName); //原函数入口
if pShMem^.lpOldExtTextOutA <> nil then
begin
//pShMem^.lpOldExtTextOutA := Pointer($BFF21CB8);
//我的机器上有别的挂钩程序,得不到ExtTextOutA的正确地址,只好手动修改
pHookCode := @Ring0_WriteMemory; //要加载到pShMem^.Code的代码入口
CodeSize := Cardinal(@InstallApi) - Cardinal(@Ring0_WriteMemory);
CopyMemory(@pShMem^.Code, pHookCode, CodeSize); //复制代码
for i := 0 to CodeSize - 1 do
if Cardinal((@pShMem^.Code)^) = Cardinal(@pHookMem) then
begin
pInt := @pShMem^.Code; //查找代码中的pHookMem并将它替换为pShMem
pInt^ := Cardinal(pShMem);
end;
pShMem^.lpRing0_WriteMemory := @pShMem^.Code; //Ring0_WriteMemory入口
pShMem^.lpOldRing0_WriteMemory := @Ring0_WriteMemory; //原始代码入口
pShMem^.lpNewExtTextOutA := Pointer(Cardinal(@pShMem^.Code) +
Cardinal(@MyExtTextOutA) - Cardinal(@Ring0_WriteMemory)); //用户ExtTextOutA入口
CopyMemory(@pShMem^.OldCode, pShMem^.lpOldExtTextOutA, SizeOf(TLongJump)); //保存原函数代码
pShMem^.NewCode.JmpOp := csJmpCode; //产生跳转代码
pShMem^.NewCode.Addr := Pointer(Cardinal(pShMem^.lpNewExtTextOutA) -
Cardinal(pShMem^.lpOldExtTextOutA) - SizeOf(TLongJump));
pShMem^.lpSour := @pShMem^.NewCode; //新跳转代码
pShMem^.lpDes := pShMem^.lpOldExtTextOutA; //原函数入口
Ring0Fun := pShMem^.lpRing0_WriteMemory; //Ring0_WriteMemory入口
asm
MOV EAX, Ring0Fun //挂接MyExtTextOutA
CALL EAX
end;
Result := True;
Hooked := True;
end;
end;
//释放Api挂钩
function UnInstallApi: Boolean;
var
Ring0Fun: Pointer; //实际的Ring0_WriteMemory入口
begin
if not Hooked then
begin
Result := False;
Exit;
end;
pShMem^.Enabled := False;
pShMem^.AllowTake := False;
pShMem^.lpSour := @pShMem^.OldCode; //原函数代码
pShMem^.lpDes := pShMem^.lpOldExtTextOutA; //原函数入口
Ring0Fun := pShMem^.lpRing0_WriteMemory; //Ring0_WriteMemory入口
asm
MOV EAX, Ring0Fun //恢复原函数代码
CALL EAX
end;
Hooked := False;
Result := True;
end;
//创建内存映象文件,初始化Api挂接环境
function InitApiHook: Boolean;
begin
Inited := False;
Hooked := False;
hMappingFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0,
SizeOf(TShareMem), PChar(csMappingFileName)); //文件映象
if hMappingFile <> 0 then
begin
pShMem := PShareMem(MapViewOfFile(hMappingFile, FILE_MAP_WRITE, 0, 0, 0));
if pShMem <> nil then //映射视图,得到一块地址>2G被所有进程共享的空间
begin
ZeroMemory(pShMem, SizeOf(TShareMem)); //数据块清零
Inited := True;
end else begin
CloseHandle(hMappingFile); //无法创建内存块
MessageBox(GetCurrentProcess, 'Cannot create the Share Memory Block!'
, 'Error', MB_OK)
end;
end
else
MessageBox(GetCurrentProcess, 'Cannot create the Share Memory Block!'
, 'Error', MB_OK); //无法创建文件映象
Result := Inited;
end;
//关闭映象文件,释放共享内存块
function CloseApiHook: Boolean;
begin
if not Inited then
begin
Result := False;
Exit;
end;
UnInstallApi; //取消挂接
UnMapViewOfFile(pShMem); //释放内存块
CloseHandle(hMappingFile); //关闭句柄
Inited := False;
Result := True;
end;
end.
测试用主窗口单元
unit MainFrm;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TMainForm = class(TForm)
cbHook: TCheckBox;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure cbHookClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
uses ApiHook;
{$R *.DFM}
procedure TMainForm.FormCreate(Sender: TObject);
begin
InitApiHook;
InstallApi;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
CloseApiHook;
end;
procedure TMainForm.cbHookClick(Sender: TObject);
begin
if cbHook.Checked then
InstallApi
else
UnInstallApi;
end;
end.
 
 

Similar threads

I
回复
0
查看
854
import
I
I
回复
0
查看
547
import
I
I
回复
0
查看
783
import
I
I
回复
0
查看
659
import
I
I
回复
0
查看
751
import
I
后退
顶部