周未一个朋友要求用Delphi做了一个东西,用到了API HOOK,于是写了个简单的
SetOnBefore把函数安装到API之前,可在真正的api执行之前先执行我们的函数
SetOnAfter把函数安装到API之后,可在真正的api执行之后再执行我们的函数
代码写得比较急,还有很多地方可以优化,功能上也有些地方可以于改进一下,如:
替换api,能改变api的返回值等。。。以后有时间玩的时候再升级,没时间就算了。。。
如果你有兴趣转成VC的代码请共享一份给我:)
具体代码如下,其中GetOpCodeSize可参考我早期的“aspr中的精彩代码(一)(修正)、(二)”
代码:
{
Name: API Hook Lib
Version: 0.1
Author: coded by xIkUg/RCT/CCG
HomePage: http://www.wintoolspro.com, http://debugman.wintoolspro.com
CreateDate: 2006-12-03
}
unit uHookLib;
interface
uses
Windows, SysUtils;
type
PBytes = ^Byte;
TMaskTable = array [0..517] of LongWord;
var
MaskTable: TMaskTable = (
$00004000, $00004000, $00004000, $00004000,
$00008000, $00008000, $00000000, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00008000, $00008000, $00000000, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00008000, $00008000, $00000000, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00008000, $00008000, $00000000, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00008000, $00008000, $00000008, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00008000, $00008000, $00000008, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00008000, $00008000, $00000008, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00008000, $00008000, $00000008, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00004000, $00004000,
$00000008, $00000008, $00001008, $00000018,
$00002000, $00006000, $00000100, $00004100,
$00000000, $00000000, $00000000, $00000000,
$00000100, $00000100, $00000100, $00000100,
$00000100, $00000100, $00000100, $00000100,
$00000100, $00000100, $00000100, $00000100,
$00000100, $00000100, $00000100, $00000100,
$00004100, $00006000, $00004100, $00004100,
$00004000, $00004000, $00004000, $00004000,
$00004000, $00004000, $00004000, $00004000,
$00004000, $00004000, $00004000, $00004000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00002002, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000020, $00000020, $00000020, $00000020,
$00000000, $00000000, $00000000, $00000000,
$00000100, $00002000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000100, $00000100, $00000100, $00000100,
$00000100, $00000100, $00000100, $00000100,
$00002000, $00002000, $00002000, $00002000,
$00002000, $00002000, $00002000, $00002000,
$00004100, $00004100, $00000200, $00000000,
$00004000, $00004000, $00004100, $00006000,
$00000300, $00000000, $00000200, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00000100, $00000100, $00000000, $00000000,
$00004000, $00004000, $00004000, $00004000,
$00004000, $00004000, $00004000, $00004000,
$00000100, $00000100, $00000100, $00000100,
$00000100, $00000100, $00000100, $00000100,
$00002000, $00002000, $00002002, $00000100,
$00000000, $00000000, $00000000, $00000000,
$00000008, $00000000, $00000008, $00000008,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00004000, $00004000,
$00004000, $00004000, $00004000, $00004000,
$FFFFFFFF, $FFFFFFFF, $00000000, $FFFFFFFF,
$00000000, $00000000, $00000000, $00000000,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$00002000, $00002000, $00002000, $00002000,
$00002000, $00002000, $00002000, $00002000,
$00002000, $00002000, $00002000, $00002000,
$00002000, $00002000, $00002000, $00002000,
$00004000, $00004000, $00004000, $00004000,
$00004000, $00004000, $00004000, $00004000,
$00004000, $00004000, $00004000, $00004000,
$00004000, $00004000, $00004000, $00004000,
$00000000, $00000000, $00000000, $00004000,
$00004100, $00004000, $FFFFFFFF, $FFFFFFFF,
$00000000, $00000000, $00000000, $00004000,
$00004100, $00004000, $FFFFFFFF, $00004000,
$00004000, $00004000, $00004000, $00004000,
$00004000, $00004000, $00004000, $00004000,
$FFFFFFFF, $FFFFFFFF, $00004100, $00004000,
$00004000, $00004000, $00004000, $00004000,
$00004000, $00004000, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$00000000, $00000000, $00000000, $00000000,
$00000000, $00000000, $00000000, $00000000,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$00000000, $FFFFFFFF, $FFFFFFFF, $FFFFFFFF,
$FFFFFFFF, $FFFFFFFF
);
function SetOnBefore(const DllName: string; const ApiName: string;
HookProc: Pointer): Boolean;
function SetOnAfter(const DllName: string; const ApiName: string;
HookProc: Pointer): Boolean;
function GetOpCodeSize(Start: Pointer; Tlb: TMaskTable): integer; stdcall;
implementation
var
JMPGate: array [0..4] of byte = (
$E9, $00, $00, $00, $00 // JMP XXXXXXXX
);
// HookProc offset is 36
// HookApi offset is 82
BeforeStub: array [0..93] of byte = (
$58, // 0 pop eax
$EB, $08, // 1 jmp short 0040100B
$00, $00, $00, $00, // 3 dd 00000000
$00, $00, $00, $00, // 7 dd 00000000
$E8, $00, $00, $00, $00, // 11 call 00401010
$59, // 16 pop ecx
$81, $E9, $10, $10, $40, $00, // 17 sub ecx, 00401010
$89, $A1, $03, $10, $40, $00, // 23 mov [ecx+401003], esp
$89, $81, $07, $10, $40, $00, // 29 mov [ecx+401007], eax
$E8, $36, $01, $00, $00, // 35 call HookProc
$8B, $44, $24, $FC, // 40 mov eax, [esp - 4]
$E8, $00, $00, $00, $00, // 44 call 0040102D
$59, // 49 pop ecx
$89, $44, $24, $FC, // 50 mov [esp - 4], eax
$81, $E9, $31, $10, $40, $00, // 54 sub ecx, 0040102D
$8B, $A1, $03, $10, $40, $00, // 60 mov esp, [ecx+401003]
$8B, $81, $07, $10, $40, $00, // 66 mov eax, [ecx+401007]
$50, // 72 push eax
$90, $90, $90, $90, // 73
$90, $90, $90, $90,
$90, $90, $90, $90,
$90, $90, $90, $90,
$E9, $18, $01, $00, $00 // 89 jmp HookedApi
);
AfterStub: array [0..129] of Byte = (
$58, // 00 pop eax
$EB, $0C, // 01 jmp short 0040100F
$00, $00, $00, $00, // 03 dd 00000000
$00, $00, $00, $00, // 07 add [eax], al
$00, $00, $00, $00, // 0B add [eax], al
$E8, $00, $00, $00, $00, // 0F call 00401014
$59, // 14 pop ecx
$81, $E9, $14, $10, $40, $00, // 15 sub ecx, 00401014
$89, $A1, $03, $10, $40, $00, // 1B mov [ecx+401003], esp
$89, $81, $07, $10, $40, $00, // 21 mov [ecx+401007], eax
$8D, $89, $43, $10, $40, $00, // 27 lea ecx, [ecx+401043]
$51, // 2D push ecx
$90, // 2E nop
$90, // 2F nop
$90, // 30 nop
$90, // 31 nop
$90, // 32 nop
$90, // 33 nop
$90, // 34 nop
$90, // 35 nop
$90, // 36 nop
$90, // 37 nop
$90, // 38 nop
$90, // 39 nop
$90, // 3A nop
$90, // 3B nop
$90, // 3C nop
$90, // 3D nop
$E9, $57, $01, $00, $00, // 3E jmp 0040119A
$8B, $5C, $24, $FC, // 43 mov ebx, [esp-4]
$E8, $00, $00, $00, $00, // 47 call 0040104C
$59, // 4C pop ecx
$89, $5C, $24, $FC, // 4D mov [esp-4], ebx
$81, $E9, $4C, $10, $40, $00, // 51 sub ecx, 0040104C
$89, $81, $0B, $10, $40, $00, // 57 mov [ecx+40100B], eax
$8B, $A1, $03, $10, $40, $00, // 5D mov esp, [ecx+401003]
$E8, $32, $01, $00, $00, // 63 call 0040119A
$E8, $00, $00, $00, $00, // 68 call 0040106D
$59, // 6D pop ecx
$81, $E9, $6D, $10, $40, $00, // 6E sub ecx, 0040106D
$8B, $81, $07, $10, $40, $00, // 74 mov eax, [ecx+401007]
$50, // 7A push eax
$8B, $81, $0B, $10, $40, $00, // 7B mov eax, [ecx+40100B]
$C3 // 81 retn
);
function GetOpCodeSize(Start: Pointer; Tlb: TMaskTable): integer;
var
pOPCode: PBytes;
t, c: LongWord;
dh, dl, al: byte;
begin
result := -1;
t := 0;
pOPCode := Start;
repeat
t := t and $F7;
c := pOPCode^;
pOpCode := Pointer((DWORD(pOpCode) + 1));
t := t or Tlb[c];
until ((t and $000000FF) and 8) = 0;
if (c = $0F6) or (c = $0F7) then
begin
t := t or $00004000;
if (pOpCode^ and $38) = 0 then
t := t or $00008000;
end
else if (c = $0CD) then
begin
t := t or $00000100;
if pOpCode^ = $20 then
t := t or $00000400;
end
else if (c = $0F) then
begin
al := pOpCode^;
pOpCode := Pointer((DWORD(pOpCode) + 1));
t := t or Tlb[al + $100];
if t = $FFFFFFFF then
Exit;
end;
if (((t and $0000FF00) shr 8) and $80) <> 0 then
begin
dh := (t and $0000FF00) shr 8;
dh := dh xor $20;
if (c and 1) = 0 then
dh := dh xor $21;
t := t and $FFFF00FF;
t := t or (dh shl 8);
end;
if (((t and $0000FF00) shr 8) and $40) <> 0 then
begin
al := pOpCode^;
pOpCode := Pointer((DWORD(pOpCode) + 1));
c := al;
c := c or (al shl 8);
c := c and $C007;
if (c and $0000FF00) <> $C000 then
begin
if ((t and $000000FF) and $10) = 0 then
begin
if (c and $000000FF) = 4 then
begin
al := pOpCode^;
pOpCode := Pointer((DWORD(pOpCode) + 1));
al := al and 7;
c := c and $0000FF00;
c := c or al;
end;
if (c and $0000FF00) <> $4000 then
begin
if (c and $0000FF00) = $8000 then
begin
t := t or 4;
end
else if c = 5 then
t := t or 4;
end
else
begin
t := t or 1;
end;
end
else
begin
if (c <> 6) then
begin
if (c and $0000FF00) = $4000 then
t := t or 1
else if (c and $0000FF00) = $8000 then
t := t or 2;
end
else
t := t or 2;
end;
end;
end;
if (((t and $000000FF)) and $20) <> 0 then
begin
dl := (t and $000000FF);
dl := dl xor 2;
t := t and $FFFFFF00;
t := t or dl;
if (dl and $10) = 0 then
begin
dl := dl xor 6;
t := t and $FFFFFF00;
t := t or dl;
end;
end;
if (((t and $0000FF00) shr 8) and $20) <> 0 then
begin
dh := (t and $0000FF00) shr 8;
dh := dh xor 2;
t := t and $FFFF00FF;
t := t or (dh shl 8);
if (dh and $10) = 0 then
begin
dh := dh xor 6;
t := t and $FFFFFF00;
t := t or dh;
end;
end;
result := DWORD(pOPCode) - DWORD(Start);
t := t and $707;
result := result + (t and $000000FF); //1条指令不可能大过255个字节
result := result + ((t and $0000FF00) shr 8);
end;
function HookCode(const DllName: string; const ApiName: string;
HookProc: Pointer): Boolean;
begin
end;
function SetOnBefore(const DllName: string; const ApiName: string;
HookProc: Pointer): Boolean;
var
ApiEntry: Pointer;
DllHandle: THandle;
ReplaceCodeSize: Integer;
OpCode: array [0..15] of byte;
StubPtr: Pointer;
Addr: LongWord;
RetSize: LongWord;
begin
Result := False;
DllHandle := GetModuleHandle(PChar(DllName));
if DllHandle = 0 then
begin
DllHandle := LoadLibrary(PChar(DllName));
if DllHandle = 0 then Exit;
end;
ApiEntry := GetProcAddress(DllHandle, PChar(ApiName));
if ApiEntry = nil then Exit;
ReplaceCodeSize := GetOpCodeSize(ApiEntry, MaskTable);
while ReplaceCodeSize < 5 do
begin
ReplaceCodeSize := ReplaceCodeSize +
GetOpCodeSize(Pointer(LongWord(ApiEntry) + ReplaceCodeSize), MaskTable);
end;
if ReplaceCodeSize > 16 then Exit;
if VirtualProtect(ApiEntry, ReplaceCodeSize, PAGE_READWRITE, nil) then
Exit;
CopyMemory(@OpCode, ApiEntry, ReplaceCodeSize);
StubPtr := VirtualAlloc(nil, SizeOf(BeforeStub), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if StubPtr = nil then Exit;
CopyMemory(StubPtr, @BeforeStub, SizeOf(BeforeStub));
// 求HookProc的地址
Addr := LongWord(HookProc) - LongWord(StubPtr) - 35 - 5;
// 写入HookProc的地址
PDWORD(LongWord(StubPtr) + 36)^ := Addr;
// 求HookedApi的地址
Addr := LongWord(ApiEntry) + ReplaceCodeSize - LongWord(StubPtr) - 89 - 5;
// 写入HookedApi的地址
PDWORD(LongWord(StubPtr) + 90)^ := Addr;
// 写入被Hook掉的OpCode
CopyMemory(Pointer(LongWord(StubPtr) + 73), @OpCode, ReplaceCodeSize);
// 改写Api入口地址
Addr := LongWord(StubPtr) - LongWord(ApiEntry) - 5;
PDWORD(LongWord(@JMPGate) + 1)^ := Addr;
WriteProcessMemory(GetCurrentProcess, ApiEntry, @JMPGate, SizeOf(JMPGate), RetSize);
// CopyMemory(ApiEntry, @JMPGate, SizeOf(JMPGate));
Result := True;
end;
function SetOnAfter(const DllName: string; const ApiName: string;
HookProc: Pointer): Boolean;
var
ApiEntry: Pointer;
DllHandle: THandle;
ReplaceCodeSize: Integer;
OpCode: array [0..15] of byte;
StubPtr: Pointer;
Addr: LongWord;
RetSize: LongWord;
begin
Result := False;
DllHandle := GetModuleHandle(PChar(DllName));
if DllHandle = 0 then
begin
DllHandle := LoadLibrary(PChar(DllName));
if DllHandle = 0 then Exit;
end;
ApiEntry := GetProcAddress(DllHandle, PChar(ApiName));
if ApiEntry = nil then Exit;
ReplaceCodeSize := GetOpCodeSize(ApiEntry, MaskTable);
while ReplaceCodeSize < 5 do
begin
ReplaceCodeSize := ReplaceCodeSize +
GetOpCodeSize(Pointer(LongWord(ApiEntry) + ReplaceCodeSize), MaskTable);
end;
if ReplaceCodeSize > 16 then Exit;
if VirtualProtect(ApiEntry, ReplaceCodeSize, PAGE_READWRITE, nil) then
Exit;
CopyMemory(@OpCode, ApiEntry, ReplaceCodeSize);
StubPtr := VirtualAlloc(nil, SizeOf(AfterStub), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if StubPtr = nil then Exit;
CopyMemory(StubPtr, @AfterStub, SizeOf(AfterStub));
// 求HookProc的地址
Addr := LongWord(HookProc) - LongWord(StubPtr) - $63 - 5;
// 写入HookProc的地址
PDWORD(LongWord(StubPtr) + $64)^ := Addr;
// 求HookedApi的地址
Addr := LongWord(ApiEntry) + ReplaceCodeSize - LongWord(StubPtr) - $3E - 5;
// 写入HookedApi的地址
PDWORD(LongWord(StubPtr) + $3F)^ := Addr;
// 写入被Hook掉的OpCode
CopyMemory(Pointer(LongWord(StubPtr) + $2E), @OpCode, ReplaceCodeSize);
// 改写Api入口地址
Addr := LongWord(StubPtr) - LongWord(ApiEntry) - 5;
PDWORD(LongWord(@JMPGate) + 1)^ := Addr;
WriteProcessMemory(GetCurrentProcess, ApiEntry, @JMPGate, SizeOf(JMPGate), RetSize);
// CopyMemory(ApiEntry, @JMPGate, SizeOf(JMPGate));
Result := True;
end;
end.