Hook API的原理其实是通过核心函数强制修改原API的头部指针,使其无条件跳转到自定义函数指针来实现的,如果学过汇编原理,其实就是jmp xxx
library HookComPort;
uses
Windows,
SysUtils,
Classes;
type
TCreateFile = function(lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: DWORD; lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle; stdcall;
TWriteFile = function(hFile: THandle; const Buffer; nNumberOfBytesToWrite: DWORD; var lpNumberOfBytesWritten: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
TReadFile = function(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD; var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
TMessageBox = function(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
TImportCode = packed record
JumpInstruction: Word;
AddressOfPointerToFunction: PPointer;
end;
PImportCode = ^TImportCode;
PImage_Import_Entry = ^Image_Import_Entry;
Image_Import_Entry = record
Characteristics: DWORD;
TimeDateStamp: DWORD;
MajorVersion: Word;
MinorVersion: Word;
Name: DWORD;
LookupTable: DWORD;
end;
TCallBack = packed record
FileName: array [0..255] of char;
FileHandle: THandle;
MainHandle: THandle;
CreaetFile_Msg: Cardinal;
ReadFile_Msg: Cardinal;
WriteFile_Msg: Cardinal;
end;
var
hMappingFile: THandle = INVALID_HANDLE_VALUE;
pCallBack: ^TCallBack;
HookHandle: THandle = INVALID_HANDLE_VALUE;
OldCreateFile: TCreateFile = nil;
OldWriteFile: TWriteFile = nil;
OldReadFile: TReadFile = nil;
OldMessageBox: TMessageBox = nil;
{$R *.res}
function FinalFunctionAddress(Code: Pointer): Pointer;
var
func: PImportCode;
begin
Result := Code;
if Code = nil then exit;
try
func:=code;
if (func.JumpInstruction = $25FF) then Result := func.AddressOfPointerToFunction^;
except
Result := nil;
end;
end;
function PatchAddress(OldFunc, NewFunc: Pointer): Integer;
var
BeenDone: TList;
function PatchAddressInModule(hModule: THandle; OldFunc, NewFunc: Pointer): Integer;
var
Dos: PImageDosHeader;
NT: PImageNTHeaders;
ImportDesc: PImage_Import_Entry;
rva: DWORD;
func: PPointer; DLL: String; f: Pointer; written: DWORD;
begin
Result:=0;
Dos := Pointer(hModule);
if BeenDone.IndexOf(Dos) >= 0 then exit;
BeenDone.Add(Dos);
OldFunc := FinalFunctionAddress(OldFunc);
if IsBadReadPtr(Dos,SizeOf(TImageDosHeader)) then exit;
if Dos.e_magic <> IMAGE_DOS_SIGNATURE then exit;
NT := Pointer(Integer(Dos) + dos._lfanew);
RVA := NT^.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
if RVA = 0 then exit;
ImportDesc := pointer(integer(Dos) + RVA);
while (ImportDesc^.Name <> 0) do
begin
DLL := PChar(Integer(Dos) + ImportDesc^.Name);
PatchAddressInModule(GetModuleHandle(PChar(DLL)), OldFunc, NewFunc);
Func := Pointer(Integer(DOS) + ImportDesc.LookupTable);
while Func^ <> nil do
begin
f := FinalFunctionAddress(Func^);
if f = OldFunc then
begin
WriteProcessMemory(GetCurrentProcess, Func, @NewFunc, 4, written);
If Written > 0 then Inc(Result);
end;
Inc(Func);
end;
Inc(ImportDesc);
end;
end;
begin
BeenDone := TList.Create;
try
Result := PatchAddressInModule(GetModuleHandle(nil), OldFunc, NewFunc);
finally
BeenDone.Free;
end;
end;
function GetMsgProc(code: integer; removal: integer; msg: Pointer): Integer; stdcall;
begin
Result := 0;
end;
procedure StartHook; stdcall;
begin
HookHandle := SetWindowsHookEx(WH_MAXHOOK, @GetMsgProc, LoadLibrary('HookComPort.Dll'), 0);
end;
procedure StopHook; stdcall;
begin
UnhookWindowsHookEx(HookHandle);
end;
function MyMessageBox(hWnd: HWND; lpText, lpCaption: PAnsiChar; uType: UINT): Integer; stdcall;
begin
Result := OldMessageBox(hWnd, lpText, PChar(String(lpCaption) + ':)'), uType);
end;
function MyCreateFile(lpFileName: PAnsiChar; dwDesiredAccess, dwShareMode: DWORD; lpSecurityAttributes: PSecurityAttributes; dwCreationDisposition, dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle; stdcall;
begin
Result := OldCreateFile(lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile);
if StriComp(lpFileName, pCallBack.FileName) = 0 then
begin
pCallBack.FileHandle := Result;
PostMessage(pCallBack.MainHandle, pCallBack.CreaetFile_Msg, Result, Result);
end;
end;
function MyWriteFile(hFile: THandle; const Buffer; nNumberOfBytesToWrite: DWORD; var lpNumberOfBytesWritten: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
var
Data: array of char;
begin
Result := OldWriteFile(hFile, Buffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
if hFile = pCallBack.FileHandle then
begin
SetLength(Data, nNumberOfBytesToWrite);
CopyMemory(Data, @Buffer, nNumberOfBytesToWrite);
PostMessage(pCallBack.MainHandle, pCallBack.WriteFile_Msg, GlobalAddAtom(PChar(Data)), nNumberOfBytesToWrite + 1);
end;
end;
function MyReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD; var lpNumberOfBytesRead: DWORD; lpOverlapped: POverlapped): BOOL; stdcall;
var
Data: array of char;
begin
Result := OldReadFile(hFile, Buffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);
if hFile = pCallBack.FileHandle then
begin
SetLength(Data, nNumberOfBytesToRead);
CopyMemory(Data, @Buffer, nNumberOfBytesToRead);
PostMessage(pCallBack.MainHandle, pCallBack.ReadFile_Msg, GlobalAddAtom(PChar(Data)), nNumberOfBytesToRead + 1);
end;
end;
procedure HookComPortOn;
begin
if hMappingFile = INVALID_HANDLE_VALUE then
begin
hMappingFile := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TCallBack), 'HookComPort');
pCallBack := MapViewOfFile(hMappingFile, FILE_MAP_WRITE or FILE_MAP_READ, 0, 0, 0);
end;
if @OldMessageBox = nil then
begin
@OldMessageBox := FinalFunctionAddress(@MessageBoxA);
PatchAddress(@OldMessageBox, @MyMessageBox);
end;
if @OldCreateFile = nil then
begin
@OldCreateFile := FinalFunctionAddress(@CreateFileA);
PatchAddress(@OldCreateFile, @MyCreateFile);
end;
if @OldWriteFile = nil then
begin
@OldWriteFile := FinalFunctionAddress(@WriteFile);
PatchAddress(@OldWriteFile, @MyWriteFile);
end;
if @OldReadFile = nil then
begin
@OldReadFile := FinalFunctionAddress(@ReadFile);
PatchAddress(@OldReadFile, @MyReadFile);
end;
end;
procedure HookComPortOff;
begin
if hMappingFile <> INVALID_HANDLE_VALUE then
begin
UnMapViewOfFile(pCallBack);
CloseHandle(hMappingFile);
end;
if @OldMessageBox <> nil then PatchAddress(@MyMessageBox, @OldMessageBox);
if @OldCreateFile <> nil then PatchAddress(@MyCreateFile, @OldCreateFile);
if @OldWriteFile <> nil then PatchAddress(@MyWriteFile, @OldWriteFile);
if @OldReadFile <> nil then PatchAddress(@MyReadFile, @OldReadFile);
end;
procedure DLLEntryPoint(dwReason: DWord);
begin
case dwReason of
DLL_PROCESS_ATTACH: HookComPortOn;
DLL_PROCESS_DETACH: HookComPortOff;
end;
end;
exports
StartHook,
StopHook;
begin
DllProc := @DLLEntryPoint;
DLLEntryPoint(DLL_PROCESS_ATTACH);
end.