首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 攔截他程式網路封包:API Hook 注入目標進程攔截 Send/Recv 完整實戰模板

     編輯:Delphi

三種攔截方案比較

方案原理優點缺點
網卡混雜模式驅動層抓取所有封包全網路可見需驅動簽名、資料量大、權限高
API Hook (用戶態)注入 DLL 修改目標進程 IAT/EAT精準針對單進程、無需驅動僅限用戶態、可能被反 Hook 偵測
代理 DLL替換系統 DLL (如 ws2_32.dll)透明攔截系統穩定性風險大、簽名問題

本文實作**用戶態 API Hook**:訊息 Hook 注入 → GetProcAddress 取得真實位址 → 覆寫 JMP 指令 → 執行自訂邏輯 → 恢復呼叫真實 API。

架構:Hook.dll + 控制程式

Hook.dll 核心邏輯


library Hook;
uses SysUtils, Windows, Messages, APIHook;

type
  PData = ^TData;
  TData = record Hook: THandle; Hooked: Boolean; end;

var DLLData: PData;

{--- 訊息 Hook 程序 ---}
procedure HookProc(nCode, wParam, lParam: LongWord); stdcall;
begin
  if not DLLData^.Hooked then begin HookAPI; DLLData^.Hooked := True; end;
  CallNextHookEx(DLLData^.Hook, nCode, wParam, lParam);
end;

{--- 安裝/卸載 ---}
function InstallHook(TargetWnd: LongWord): Boolean; stdcall;
var Tid: LongWord;
begin
  Result := False;
  Tid := GetWindowThreadProcessId(TargetWnd, nil);
  DLLData^.Hook := SetWindowsHookEx(WH_GETMESSAGE, @HookProc, HInstance, Tid);
  Result := DLLData^.Hook > 0;
end;

procedure UnHook; stdcall;
begin UnHookAPI; UnhookWindowsHookEx(DLLData^.Hook); end;

{--- DLL 入口:共享記憶體儲存全域狀態 ---}
procedure MyDLLHandler(Reason: Integer);
var FHandle: THandle;
begin
  case Reason of
    DLL_PROCESS_ATTACH:
      begin
        FHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, $FFFF, 'MYDLLDATA');
        if FHandle = 0 then FHandle := OpenFileMapping(FILE_MAP_ALL_ACCESS, False, 'MYDLLDATA');
        DLLData := MapViewOfFile(FHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
      end;
    DLL_PROCESS_DETACH:
      if Assigned(DLLData) then begin UnmapViewOfFile(DLLData); DLLData := nil; end;
  end;
end;

exports InstallHook, UnHook, HookProc;
begin DLLProc := @MyDLLHandler; MyDLLHandler(DLL_PROCESS_ATTACH); DLLData^.Hooked := False; end.

APIHook.pas:Send/Recv 具體 Hook


unit APIHook;
interface uses SysUtils, Windows, WinSock;
type
  TSockProc = function(s: TSocket; var Buf; Len, Flags: Integer): Integer; stdcall;
  TJmpCode = packed record
    JmpCode: Byte;      // $E9 (JMP REL32) 或 $B8 (MOV EAX) + FF E0 (JMP EAX)
    Address: TSockProc;
    MovEAX: array[0..2] of Byte;
  end;

var
  OldSend, OldRecv: TSockProc;
  JmpCode: TJmpCode;
  OldCode: array[0..1] of TJmpCode;
  AddSend, AddRecv: Pointer;
  ProcessHandle: THandle;

implementation

{--- MySend: 攔截發送 ---}
function MySend(s: TSocket; var Buf; Len, Flags: Integer): Integer; stdcall;
var Dw: Cardinal;
begin
  // 處理發送資料 (此處僅 Beep 示意)
  MessageBeep(1000);
  WriteProcessMemory(ProcessHandle, AddSend, @OldCode[0], 8, Dw); // 恢復原指令
  Result := OldSend(s, Buf, Len, Flags); // 呼叫真實 Send
  JmpCode.Address := @MySend;
  WriteProcessMemory(ProcessHandle, AddSend, @JmpCode, 8, Dw); // 重新 Hook
end;

{--- MyRecv: 攔截接收 ---}
function MyRecv(s: TSocket; var Buf; Len, Flags: Integer): Integer; stdcall;
var Dw: Cardinal;
begin
  MessageBeep(1000);
  WriteProcessMemory(ProcessHandle, AddRecv, @OldCode[1], 8, Dw);
  Result := OldRecv(s, Buf, Len, Flags);
  JmpCode.Address := @MyRecv;
  WriteProcessMemory(ProcessHandle, AddRecv, @JmpCode, 8, Dw);
end;

{--- 安裝 Hook ---}
procedure HookAPI;
var Dw: Cardinal; H: THandle;
begin
  ProcessHandle := GetCurrentProcess;
  H := LoadLibrary('ws2_32.dll');
  AddSend := GetProcAddress(H, 'send');
  AddRecv := GetProcAddress(H, 'recv');
  // JMP 短指令模板 (x86)
  JmpCode.JmpCode := $B8; // MOV EAX, addr
  JmpCode.MovEAX[0] := $FF; JmpCode.MovEAX[1] := $E0; JmpCode.MovEAX[2] := 0; // JMP EAX
  ReadProcessMemory(ProcessHandle, AddSend, @OldCode[0], 8, Dw);
  JmpCode.Address := @MySend; WriteProcessMemory(ProcessHandle, AddSend, @JmpCode, 8, Dw);
  ReadProcessMemory(ProcessHandle, AddRecv, @OldCode[1], 8, Dw);
  JmpCode.Address := @MyRecv; WriteProcessMemory(ProcessHandle, AddRecv, @JmpCode, 8, Dw);
  OldSend := AddSend; OldRecv := AddRecv;
end;

{--- 卸載 Hook ---}
procedure UnHookAPI;
var Dw: Cardinal;
begin
  WriteProcessMemory(ProcessHandle, AddSend, @OldCode[0], 8, Dw);
  WriteProcessMemory(ProcessHandle, AddRecv, @OldCode[1], 8, Dw);
end;
end.

控制程式:載入 DLL 並安裝


type
  TInstallHook = function(Wnd: THandle): Boolean; stdcall;
  TUnHook = procedure; stdcall;

procedure TForm1.Button1Click(Sender: TObject);
var H: THandle; Wnd: THandle;
begin
  Wnd := FindWindow(nil, '目標視窗標題');
  if not IsWindow(Wnd) then begin ShowMessage('找不到視窗'); Exit; end;
  H := LoadLibrary('Hook.dll');
  @InstallHook := GetProcAddress(H, 'InstallHook');
  @UnHook := GetProcAddress(H, 'UnHook');
  if InstallHook(Wnd) then ShowMessage('Hook 成功');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin UnHook; end;

關鍵技術解析

  • WH_GETMESSAGE Hook:注入目標執行緒訊息循環,DLL 隨進程載入
  • 共享記憶體:CreateFileMapping + MapViewOfFile 實現 DLL 多進程實例共享 Hooked 狀態
  • Inline Hook:直接修改目標函數開頭機器碼 (JMP 到自訂函數)
  • 原子切換:WriteProcessMemory 寫入 8 字節 (x86 JMP 指令長度),執行自訂 → 恢復 → 呼叫原函數 → 重新 Hook
  • x64 注意:指令長度、呼叫慣例、絕對跳轉 (JMP RAX) 不同,需重寫模板

風險與防禦

  • 目標進程可能掃描自身代碼段檢測 Hook (CRC/雜湊)
  • 殺毒/EDR 視為惡意行為 (代碼注入、IAT 修改)
  • 現代替代:ETW (Event Tracing for Windows)、WFP (Windows Filtering Platform)、用戶態網路監控 API、WinDivert (驅動層)

總結

此模板展示經典 **DLL 注入 + Inline Hook** 攔截 ws2_32.dll!send/recv。理解訊息 Hook 注入機制、共享記憶體跨進程狀態、JMP 指令覆寫、原子恢復/重 Hook 流程,是 Windows 逆向與安全研究核心技能。實戰務必處理 x86/x64 差異、多執行緒競爭、例外安全、反偵測等工程化細節。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved