完成,另外可以使用madCollection来实现.
贡献代码:
function YcInstallProcHook(ProcAddress, HookProc, OrgCallProc: Pointer): Boolean;
function YcUnInstallProcHook(OrgCallProc: Pointer): Boolean;
//--------------------------------------------------------------------------------------------------
function ReadProtectedMemory(Address: Pointer
var Buffer
Count: Cardinal): Boolean;
var
N: Cardinal;
begin
Result := ReadProcessMemory(GetCurrentProcess, Address, @Buffer, Count, N);
Result := Result and (N = Count);
end;
function WriteProtectedMemory(Address: Pointer
const Buffer
Count: Cardinal): Boolean;
var
N: Cardinal;
begin
Result := WriteProcessMemory(GetCurrentProcess, Address, @Buffer, Count, N);
Result := Result and (N = Count);
end;
type
TJumpCode = packed record
Jmp: Byte
// jmp Offset
Offset: Integer;
end;
TOrgCallCode = packed record
Code: array[0..SizeOf(TJumpCode) + 4] of Byte;
Jmp: Byte
// jmp Offset
Offset: Integer;
Address: Pointer;
end;
function YcGetRelocAddress(ProcAddress: Pointer): Pointer;
type
TRelocationRec = packed record
Jump: Word;
Address: PPointer;
end;
var
Relocation: TRelocationRec;
Data: Byte;
begin
Result := ProcAddress;
// the relocation table might be protected
if ReadProtectedMemory(ProcAddress, Data, SizeOf(Data)) then
if Data = $FF then // ProcAddress is in a DLL or package
if ReadProtectedMemory(ProcAddress, Relocation, SizeOf(Relocation)) then
Result := Relocation.Address^;
end;
function AllocateHWnd(Method: TWndMethod): HWND;
begin
Result := Forms.AllocateHWnd(Method);
end;
procedure DeallocateHWnd(Wnd: HWND);
begin
Forms.DeallocateHWnd(Wnd);
end;
type
TModRM = record
Mode: Byte;
RegOp: Byte;
RM: Byte;
end;
function GetModRM(B: Byte): TModRM;
begin
Result.Mode := B shr 6;
Result.RegOp := (B shr 3) and $07;
Result.RM := B and $07;
end;
function GetDisassembledByteCount(const Bytes: array of Byte): Integer;
var
I, LastByteCount: Integer;
ModRM: TModRM;
begin
Result := 0;
LastByteCount := 0;
I := 0;
while I < Length(Bytes) do
begin
LastByteCount := Result;
case Bytes of
$53..$56:
// push reg
$8B, $3B: // mov/cmp
begin
Inc(I);
ModRM := GetModRM(Bytes);
case ModRM.Mode of
$00:
if ModRM.RM = $07 then
Inc(I, 2)
// mov reg, disp16
$01:
Inc(I)
// mov reg, [reg]+disp8
$02:
Inc(I, 2)
// mov reg, [reg]+disp16
end;
end;
$E8:
Inc(I, 4)
// call rel32
$5B..$5E:
// pop reg
$C3:
// ret
$E9:
Inc(I, 4)
// jmp rel32
$83: // add
Inc(I, 2);
$89:
Inc(I, 2);
end;
Inc(I);
Result := I;
end;
if I > Length(Bytes) then
Result := LastByteCount;
end;
function YcInstallProcHook(ProcAddress, HookProc, OrgCallProc: Pointer): Boolean;
var
Code: TJumpCode;
OrgCallCode: TOrgCallCode;
I, Count: Integer;
begin
ProcAddress := YcGetRelocAddress(ProcAddress);
Result := False;
if Assigned(ProcAddress) and Assigned(HookProc) then
begin
{$IFDEF madCodeHook}
Result := HookCode(ProcAddress, HookProc, OrgCallProc);
Exit;
{$ELSE}
if OrgCallProc <> nil then
begin
if ReadProtectedMemory(ProcAddress, OrgCallCode, SizeOf(OrgCallCode.Code)) then
begin
Count := GetDisassembledByteCount(OrgCallCode.Code);
for I := Count to SizeOf(OrgCallCode.Code) do
OrgCallCode.Code := $90
// NOP
OrgCallCode.Jmp := $E9;
OrgCallCode.Offset := (Integer(ProcAddress) {+ SizeOf(Code)} + Count) -
Integer(OrgCallProc) -
(SizeOf(OrgCallCode) - SizeOf(OrgCallCode.Address));
OrgCallCode.Address := ProcAddress;
WriteProtectedMemory(OrgCallProc, OrgCallCode, SizeOf(OrgCallCode));
FlushInstructionCache(GetCurrentProcess, OrgCallProc, SizeOf(OrgCallCode));
end;
end;
Code.Jmp := $E9;
Code.Offset := Integer(HookProc) - (Integer(ProcAddress)) - SizeOf(Code);
{ The strange thing is that something overwrites the $e9 with a "PUSH xxx"
}
if WriteProtectedMemory(Pointer(Cardinal(ProcAddress)), Code, SizeOf(Code)) then
begin
FlushInstructionCache(GetCurrentProcess, ProcAddress, SizeOf(Code));
Result := True;
end;
{$ENDIF}
end;
end;
function YcUnInstallProcHook(OrgCallProc: Pointer): Boolean;
var
OrgCallCode: TOrgCallCode;
ProcAddress: Pointer;
begin
Result := False;
if Assigned(OrgCallProc) then
{$IFDEF madCodeHook}
Result := UnhookCode(OrgCallProc);
Exit;
{$ELSE}
if OrgCallProc <> nil then
if ReadProtectedMemory(OrgCallProc, OrgCallCode, SizeOf(OrgCallCode)) then
begin
ProcAddress := OrgCallCode.Address;
Result := WriteProtectedMemory(ProcAddress, OrgCallCode, SizeOf(TJumpCode));
FlushInstructionCache(GetCurrentProcess, ProcAddress, SizeOf(OrgCallCode));
end;
{$ENDIF}
end;