| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548 |
- {******************************************************************************}
- { CnPack For Delphi/C++Builder }
- { 中国人自己的开放源码第三方开发包 }
- { (C)Copyright 2001-2018 CnPack 开发组 }
- { ------------------------------------ }
- { }
- { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
- { 改和重新发布这一程序。 }
- { }
- { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
- { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
- { }
- { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
- { 还没有,可访问我们的网站: }
- { }
- { 网站地址:http://www.cnpack.org }
- { 电子邮件:master@cnpack.org }
- { }
- {******************************************************************************}
- unit CnInProcessAPIHook;
- {* |<PRE>
- ================================================================================
- * 软件名称:不可视工具组件包
- * 单元名称:进程内实现APIHook的单元
- * 单元作者:CodeGame
- * 备 注:
- * 开发平台:PWinXP + Delphi 2007
- * 兼容测试:暂无
- * 单元标识:$Id: CnInProcessAPIHook.pas 1146 2012-10-24 06:25:41Z liuxiaoshanzhashu@gmail.com $
- * 修改记录:2013.08.08 v1.0
- * 移植单元
- ================================================================================
- |</PRE>}
- interface
- {$I CnPack.inc}
- uses
- Windows, SysUtils, Classes;
- type
- THookType = (HT_None, HT_LONG_JMP, HT_LONG_CALL, HT_SHORT_JMP, HT_SHORT_CALL);
- PHT_LONG = ^HT_LONG;
- HT_LONG = packed record
- Long: Word;
- LongAddr: Cardinal;
- end;
- PHT_SHORT = ^HT_SHORT;
- HT_SHORT = packed record
- Short: Byte;
- ShortAddr: Cardinal;
- end;
- TOnAPIHookProc = function(const Params: array of Pointer): DWORD of object;
- { TCnHookCore }
- TCnHookCore = class(TObject)
- private
- FAddr: Pointer;
- FEvent: Pointer;
- FStyle: THookType;
- FAddrSize: Byte;
- FHooked: Boolean;
- procedure SetStyle(const Value: THookType);
- protected
- FDWSize: Cardinal;
- FCode: Word;
- FOldProtect: Cardinal;
- FBakCode: array[0..255] of Char;
- public
- constructor Create;
- procedure Hook;
- procedure UnHook;
- property Addr: Pointer read FAddr write FAddr;
- property AddrSize: Byte read FAddrSize write FAddrSize;
- property Event: Pointer read FEvent write FEvent;
- property Style: THookType read FStyle write SetStyle;
- property Hooked: Boolean read FHooked;
- end;
- PDynamicCode = ^DynamicCode;
- DynamicCode = packed record
- Push: Byte;
- Self: DWORD;
- Call: Word;
- CallAddr: Pointer;
- RetCode: Byte;
- RetXX: WORD;
- EventAddr: Pointer;
- ExtraData: Pointer;
- end;
- TOnHookProc = function(Data: PDynamicCode): DWORD of object;
- { TCnHookAddress }
- TCnHookAddress = class(TObject)
- private
- FHooker: TCnHookCore;
- FInit: Boolean;
- FHook: Boolean;
- FRetCount: Byte;
- FMutex: Boolean;
- FOnHookProc: TOnHookProc;
- FExtraData: Pointer;
- procedure SetInit(const Value: Boolean);
- procedure SetHook(const Value: Boolean);
- function GetInstructionAddr: Pointer;
- procedure SetInstructionAddr(const Value: Pointer);
- function GetInstructionSize: Byte;
- procedure SetInstructionSize(const Value: Byte);
- procedure InitHook;
- procedure UnInitHook;
- protected
- FHookMark: array[0..7] of Char;
- public
- constructor Create;
- destructor Destroy; override;
- property Init: Boolean read FInit write SetInit;
- property Hook: Boolean read FHook write SetHook;
- property RetCount: Byte read FRetCount write FRetCount;
- property InstructionAddr: Pointer read GetInstructionAddr write SetInstructionAddr;
- property InstructionSize: Byte read GetInstructionSize write SetInstructionSize;
- property Mutex: Boolean read FMutex write FMutex;
- property ExtraData: Pointer read FExtraData write FExtraData;
- property OnHookProc: TOnHookProc read FOnHookProc write FOnHookProc;
- end;
- { TCnInProcessAPIHook }
- TCnInProcessAPIHook = class(TComponent)
- private
- FHooker: TCnHookAddress;
- FDllFunction: string;
- FDllName: string;
- FActive: Boolean;
- FRestoreWhenOnHook: Boolean;
- FOnAPIHookProc: TOnAPIHookProc;
- function GetMutex: Boolean;
- procedure SetMutex(const Value: Boolean);
- function GetParamCount: Byte;
- procedure SetParamCount(const Value: Byte);
- procedure SetActive(const Value: Boolean);
- protected
- FHookMark: string;
- function OnHookProc(Data: PDynamicCode): DWORD;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- published
- property DllFunction: string read FDllFunction write FDllFunction;
- property DllName: string read FDllName write FDllName;
- property ParamCount: Byte read GetParamCount write SetParamCount;
- property Mutex: Boolean read GetMutex write SetMutex;
- property RestoreWhenOnHook: Boolean read FRestoreWhenOnHook write FRestoreWhenOnHook;
- property Active: Boolean read FActive write SetActive;
- property OnAPIHookProc: TOnAPIHookProc read FOnAPIHookProc write FOnAPIHookProc;
- end;
- implementation
- { TCnHookCore }
- constructor TCnHookCore.Create;
- begin
- SetStyle(HT_LONG_JMP);
- FAddrSize := SizeOf(HT_LONG);
- end;
- procedure TCnHookCore.SetStyle(const Value: THookType);
- begin
- if Value <> FStyle then
- begin
- FStyle := Value;
- case FStyle of
- HT_LONG_JMP:
- begin
- FCode := $25FF;
- FDWSize := SizeOf(HT_LONG);
- end;
- HT_LONG_CALL:
- begin
- FCode := $15FF;
- FDWSize := SizeOf(HT_LONG);
- end;
- HT_SHORT_JMP:
- begin
- FCode := $E9;
- FDWSize := SizeOf(HT_SHORT);
- end;
- HT_SHORT_CALL:
- begin
- FCode := $E8;
- FDWSize := SizeOf(HT_SHORT);
- end;
- end;
- if FAddrSize < FDWSize then
- FAddrSize := FDWSize;
- end;
- end;
- procedure TCnHookCore.Hook;
- var
- Code1: PHT_LONG;
- Code2: PHT_SHORT;
- Addr: Cardinal;
- begin
- if not FHooked then
- begin
- if VirtualProtect(FAddr, FAddrSize, PAGE_EXECUTE_WRITECOPY, FOldProtect) then
- begin
- FillMemory(@FBakCode[0], 256, $90);
- //备份代码
- CopyMemory(@FBakCode[0], FAddr, FAddrSize);
- case FStyle of
- HT_LONG_JMP, HT_LONG_CALL:
- begin
- Code1 := FAddr;
- Code1^.Long := FCode;
- Code1^.LongAddr := Cardinal(@FEvent);
- end;
- HT_SHORT_JMP, HT_SHORT_CALL:
- begin
- //计算相对地址
- Addr := Cardinal(FEvent) - Cardinal(FAddr) - FDWSize;
- Code2 := FAddr;
- Code2^.Short := FCode;
- Code2^.ShortAddr := Addr;
- end;
- end;
- FHooked := True;
- end;
- end;
- end;
- procedure TCnHookCore.UnHook;
- begin
- if FHooked then
- begin
- CopyMemory(FAddr, @FBakCode[0], FAddrSize);
- VirtualProtect(FAddr, FAddrSize, FOldProtect, FOldProtect);
- FHooked := False;
- end;
- end;
- { TCnHookAddress }
- function DoOnHookProc(Self: TCnHookAddress): DWORD; stdcall;
- var
- hh: THandle;
- begin
- Result := 0;
- if Assigned(Self.OnHookProc) then
- begin
- if Self.FMutex then
- begin
- hh := OpenMutex(MUTEX_ALL_ACCESS, True, Self.FHookMark);
- //如果已经有就等待
- if hh <> 0 then
- WaitForSingleObject(hh, INFINITE)
- else
- hh := CreateMutex(nil, True, Self.FHookMark); //否则创建一个
- //执行事件
- Result := Self.OnHookProc(Self.FHooker.Event);
- //销毁事件
- ReleaseMutex(hh);
- CloseHandle(hh);
- end
- else
- //执行事件
- Result := Self.OnHookProc(Self.FHooker.Event);
- end;
- end;
- constructor TCnHookAddress.Create;
- begin
- FHooker := TCnHookCore.Create;
- end;
- destructor TCnHookAddress.Destroy;
- begin
- UnInitHook;
- FHooker.UnHook;
- FHooker.Free;
- inherited;
- end;
- function TCnHookAddress.GetInstructionAddr: Pointer;
- begin
- Result := FHooker.Addr;
- end;
- procedure TCnHookAddress.SetInstructionAddr(const Value: Pointer);
- begin
- FHooker.Addr := Value;
- end;
- function TCnHookAddress.GetInstructionSize: Byte;
- begin
- Result := FHooker.AddrSize;
- end;
- procedure TCnHookAddress.SetInstructionSize(const Value: Byte);
- begin
- FHooker.AddrSize := Value;
- end;
- procedure TCnHookAddress.SetInit(const Value: Boolean);
- begin
- if FInit = Value then
- Exit; //跟上次一样则什么都不做
- case Value of
- True: //初始化
- begin
- if FInit = False then
- begin
- InitHook;
- FInit := True;
- end;
- end;
- False: //反初始化
- begin
- if FInit then
- begin
- UnInitHook;
- FInit := False;
- end;
- end;
- end;
- end;
- procedure TCnHookAddress.SetHook(const Value: Boolean);
- begin
- if FHook = Value then
- Exit; //跟上次一样则什么都不做
- case Value of
- True: //初始化
- begin
- if FHook = False then
- begin
- FHooker.Hook;
- FHook := True;
- end;
- end;
- False: //反初始化
- begin
- if FHook then
- begin
- FHooker.UnHook;
- FHook := False;
- end;
- end;
- end;
- end;
- procedure TCnHookAddress.InitHook;
- type
- PStr = ^Str;
- Str = array[0..3] of Char;
- var
- FDynamicCode: PDynamicCode;
- Mark: string;
- Value1, Value2: DWORD;
- begin
- //制定类型
- FHooker.Style := HT_SHORT_JMP;
- //分配内存
- FDynamicCode := VirtualAlloc(nil, SizeOf(DynamicCode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
- //保存地址
- FDynamicCode^.EventAddr := @DoOnHookProc;
- //写入相应语句
- FDynamicCode^.Push := $68; //PUSH
- FDynamicCode^.Self := DWORD(Self); //写上 Self
- FDynamicCode^.Call := $15FF; //CALL
- FDynamicCode^.CallAddr := @FDynamicCode^.EventAddr; //事件发生
- FDynamicCode^.RetCode := $C2; //RET
- FDynamicCode^.RetXX := FRetCount * 4; //RET XX
- FDynamicCode^.ExtraData := FExtraData; //额外数据
- //写入事件
- FHooker.Event := FDynamicCode;
- //制作 Mark
- Value1 := GetCurrentProcess;
- Value2 := DWORD(Self.InstructionAddr);
- Mark := PStr(@Value1)^ + pstr(@Value2)^;
- CopyMemory(@FHookMark[0], @Mark[1], 8);
- end;
- procedure TCnHookAddress.UnInitHook;
- var
- FDynamicCode: PDynamicCode;
- begin
- //释放 Hook
- Hook := False;
- FDynamicCode := FHooker.Event;
- FHooker.Event := nil;
- //释放内存
- VirtualFree(FDynamicCode, SizeOf(DynamicCode), MEM_DECOMMIT);
- end;
- { TCnInProcessAPIHook }
- constructor TCnInProcessAPIHook.Create(AOwner: TComponent);
- begin
- inherited;
- FRestoreWhenOnHook := True;
- FHooker := TCnHookAddress.Create;
- end;
- destructor TCnInProcessAPIHook.Destroy;
- begin
- FHooker.Free;
- inherited;
- end;
- function TCnInProcessAPIHook.GetMutex: Boolean;
- begin
- Result := FHooker.Mutex;
- end;
- procedure TCnInProcessAPIHook.SetMutex(const Value: Boolean);
- begin
- FHooker.Mutex := Value;
- end;
- function TCnInProcessAPIHook.GetParamCount: Byte;
- begin
- Result := FHooker.RetCount;
- end;
- procedure TCnInProcessAPIHook.SetParamCount(const Value: Byte);
- begin
- FHooker.RetCount := Value;
- end;
- procedure TCnInProcessAPIHook.SetActive(const Value: Boolean);
- type
- PStr = ^Str;
- Str = array[0..3] of Char;
- var
- Lib, Values: DWORD;
- tmp: string;
- begin
- if Value = FActive then
- Exit;
- FActive := Value;
- if not (csDesigning in ComponentState) then
- begin
- case Value of
- True:
- begin
- //取得地址
- Lib := LoadLibrary(PChar(FDllName));
- FHooker.InstructionAddr := GetProcAddress(Lib, PChar(FDllFunction));
- FreeLibrary(Lib);
- //固定长度
- FHooker.InstructionSize := 5;
- //事件
- FHooker.OnHookProc := OnHookProc;
- //Self
- FHooker.ExtraData := Self;
- //设置标记
- Values := GetCurrentProcess;
- tmp := PStr(@Values)^;
- FHookMark := CharUpper(PChar(FDllName + FDllFunction + tmp));
- //打开 Hook
- FHooker.Init := True;
- FHooker.Hook := True;
- end;
- False:
- begin
- //关闭 Hook
- FHooker.Hook := False;
- FHooker.Init := False;
- end;
- end;
- end;
- end;
- function TCnInProcessAPIHook.OnHookProc(Data: PDynamicCode): DWORD;
- var
- AESP: Pointer;
- OBJ: TCnInProcessAPIHook;
- Params: array of Pointer;
- Param: Pointer;
- _Handle: THandle;
- begin
- //取得 Self
- _Handle := 0;
- OBJ := Data^.ExtraData;
- if Assigned(OBJ.FOnAPIHookProc) then
- begin
- asm
- mov AESP, ESP
- end;
- Param := Pointer(DWORD(AESP) + $54); //参数开始,此处随编译器变动而变
- SetLength(Params, OBJ.ParamCount); //设置参数个数
- CopyMemory(@Params[0], Param, Obj.ParamCount * 4);
- if OBJ.Mutex then
- begin
- _Handle := OpenMutex(MUTEX_ALL_ACCESS, True, PChar(OBJ.FHookMark));
- //如果已经有就等待
- if _Handle <> 0 then
- WaitForSingleObject(_Handle, INFINITE)
- else
- _Handle := CreateMutex(nil, True, PChar(OBJ.FHookMark)); //否则创建一个
- end;
- //执行事件
- if FRestoreWhenOnHook then
- OBJ.FHooker.Hook := False;
- Result := OBJ.FOnAPIHookProc(Params);
- CopyMemory(Param, @Params[0], Obj.ParamCount * 4); //参数写回
- if FRestoreWhenOnHook then
- OBJ.FHooker.Hook := True;
- if OBJ.Mutex then
- begin
- //销毁事件
- ReleaseMutex(_Handle);
- CloseHandle(_Handle);
- end;
- end;
- end;
- end.
|