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

Delphi Hook 技術實現 DLL 注入:原理與完整程式碼解析

     編輯:Delphi

前言

DLL 注入是將自訂動態連結庫載入目標進程位址空間,進而攔截系統呼叫、修改行為或擴充功能的技術。本文詳細解析基於 Windows Hook 機制 (SetWindowsHookEx) 的 DLL 注入完整流程,包含注入端 (Caller) 與被注入 DLL (Inject.dll) 的核心程式碼與關鍵細節。

整體流程

  1. Caller 透過 FindWindow/FindWindowEx 取得目標視窗控制代碼。
  2. 用 GetWindowThreadProcessId 取得目標執行緒 ID。
  3. 呼叫 Inject.dll 匯出的 SetInjectHook(ThreadID) 安裝 Hook。
  4. Hook 程序 (GetMsgProc) 在目標執行緒內建立自訂表單 (TInjectForm) 作為控制入口。
  5. Caller 透過 FindWindow 找到注入表單,發送自訂訊息 (WM_APP) 控制目標視窗。
  6. 完成後移除 Hook、關閉注入表單。

Caller.exe 核心程式碼

procedure TestHook;
var
  hMain, hChild, hInjectForm: HWND;
  dwThreadID: DWORD;
  Msg: TMsg;
begin
  // 1. 尋找目標主視窗 (以 Program Manager 為例)
  hMain := FindWindow('Progman', nil);
  // 2. 尋找子視窗
  hChild := FindWindowEx(hMain, 0, nil, nil);
  // 3. 取得目標執行緒 ID
  dwThreadID := GetWindowThreadProcessId(hChild, nil);

  // 4. 安裝 Hook (載入 Inject.dll 並呼叫 SetInjectHook)
  SetInjectHook(dwThreadID);

  // 5. 等待訊息迴圈 (確保 Hook 程序已執行)
  GetMessage(Msg, 0, 0, 0);

  // 6. 尋找注入建立的控制表單
  hInjectForm := FindWindow(nil, 'InjectForm');
  // 7. 發送控制訊息:wParam=目標視窗控制代碼, lParam=控制參數
  SendMessage(hInjectForm, WM_APP, hChild, Integer(True));

  // 8. 關閉注入表單並清理
  SendMessage(hInjectForm, WM_CLOSE, 0, 0);
  Sleep(500);
  Assert(not IsWindow(hInjectForm));

  // 9. 移除 Hook
  SetDipsHook(0);  // 對應 SetInjectHook(0)
end;

Inject.dll 核心實作

全域變數與 Hook 安裝/移除

library Inject;

uses
  Windows, Forms, UnitInjectForm;  // 包含 TInjectForm 定義

var
  g_hHook: HHook = 0;
  g_dwThreadIDInject: DWORD = 0;
  g_hInjectForm: HWND = 0;
  fFirstTime: Boolean = True;

function SetInjectHook(dwThreadID: DWORD): Boolean; stdcall;
begin
  Result := False;
  if dwThreadID <> 0 then
  begin
    // 安裝 Hook
    Assert(g_hHook = 0);
    g_dwThreadIDInject := GetCurrentThreadId;
    // WH_GETMESSAGE: 攔截 GetMessage/PeekMessage
    g_hHook := SetWindowsHookEx(WH_GETMESSAGE, @GetMsgProc, HInstance, dwThreadID);
    Result := g_hHook <> 0;
    if Result then
    begin
      // 發送空訊息觸發 Hook 程序建立表單
      Result := PostThreadMessage(dwThreadID, WM_NULL, 0, 0);
      Sleep(500); // 等待表單建立完成
    end;
  end
  else
  begin
    // 移除 Hook
    Assert(g_hHook <> 0);
    Result := UnhookWindowsHookEx(g_hHook);
    g_hHook := 0;
  end;
end;

exports
  SetInjectHook name 'SetInjectHook';

Hook 程序:在目標執行緒建立控制表單

function GetMsgProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
  InjectForm: TInjectForm;
begin
  if fFirstTime then
  begin
    fFirstTime := False;
    // 在目標執行緒建立表單 (必須在 Hook 程序內建立)
    InjectForm := TInjectForm.Create(nil);
    g_hInjectForm := InjectForm.Handle;
  end;
  // 必須呼叫下一個 Hook,否則訊息鏈斷裂
  Result := CallNextHookEx(g_hHook, nCode, wParam, lParam);
end;

TInjectForm 訊息處理 (UnitInjectForm.pas)


unit UnitInjectForm;

interface
uses Windows, Messages, Forms, Controls;

type
  TInjectForm = class(TForm)
  private
    procedure WMApp(var Msg: TMessage); message WM_APP;
  end;

implementation

procedure TInjectForm.WMApp(var Msg: TMessage);
var
  TargetWnd: HWND;
  Enable: Boolean;
begin
  TargetWnd := HWND(Msg.WParam);
  Enable := Boolean(Msg.LParam);
  // 此處在目標進程執行緒內,可直接操作目標視窗
  // 範例:啟用/停用目標視窗
  EnableWindow(TargetWnd, Enable);
  // 回傳結果給 Caller (可選)
  Msg.Result := 1;
end;

end.

關鍵技術點總結

技術點說明
Hook 類型WH_GETMESSAGE 攔截訊息迴圈,確保在目標執行緒內執行程式碼
表單建立時機首次 Hook 程序被呼叫時 (fFirstTime 旗標)
跨進程通訊Caller 用 FindWindow 找到注入表單,發送 WM_APP 自訂訊息
清理順序發送 WM_CLOSE → 等待 → UnhookWindowsHookEx
注意事項1. 目標進程必須有訊息迴圈 (GUI 應用程式)
2. 32/64 位元必須匹配 (32-bit DLL 注入 32-bit 進程)
3. 需處理例外情況防止目標進程當機
4. 某些安全軟體會攔截 Hook 行為

安全與道德提醒

Hook 與 DLL 注入屬進階系統程式技術,僅供學習、除錯、合法擴充功能使用。惡意注入、竊取資料、繞過授權等行為違法且違反道德,嚴禁濫用。

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