實作 IShellExecuteHook 的進程內 COM 物件,註冊至系統後,可攔截所有 ShellExecute/ShellExecuteEx 呼叫。Windows 98/2000 原生支援,95/NT4 需安裝 IE 4.01+ (Active Desktop)。
資源管理器幾乎所有操作(雙擊開啟、列印、編輯、屬性、右鍵選單、開始→執行)均經由上述 API,故可廣泛監控使用者行為。
File → New → ActiveX LibraryNew → COM Object,類別名 TShellExecuteHook,介面 IShellExecuteHook。ShlObj 單元)type
TTShellExecuteHook = class(TComObject, IShellExecuteHook)
protected
function Execute(var ShellExecuteInfo: TShellExecuteInfo): HResult; stdcall;
end;
const
Class_TShellExecuteHook: TGUID = '{935FA400-243D-11D3-B06E-857B2AE2BE64}';
function TTShellExecuteHook.Execute(var ShellExecuteInfo: TShellExecuteInfo): HResult;
var
FileName: string;
fs: TFileStream;
s: string;
begin
Result := S_FALSE; // 預設繼續預設任務
with ShellExecuteInfo do begin
// 記錄:動作 + 目標檔案 + 時間
fs := TFileStream.Create('C:\ShellExecuteHook.log', fmOpenWrite or fmShareDenyNone);
try
fs.Seek(0, soFromEnd);
s := Format('%s:%s %s%s', [lpVerb, lpFile, DateTimeToStr(Now), #13#10]);
fs.Write(PChar(s)^, Length(s));
finally
fs.Free;
end;
// 範例:禁止記事本執行
FileName := UpperCase(ExtractFileName(lpFile));
if Pos('NOTEPAD', FileName) = 1 then begin
Result := S_OK; // 取消預設執行
hInstApp := 32; // 模擬錯誤碼
MessageBox(Wnd, '不允許記事本運行!', '錯誤', MB_OK or MB_ICONERROR);
end;
end;
end;
TShellExecuteInfo 關注欄位lpVerb:操作動詞 (open/print/edit/explore/properties/find 等)lpFile:目標檔案/程式路徑nShow:視窗顯示狀態(可修改)S_FALSE 繼續、S_OK 攔截阻止、錯誤碼則彈出系統錯誤訊息。會觸發遞迴攔截導致死循環。需啟動外部程序請用 CreateProcess 或 WinExec。
type
TShellExComObjectFactory = class(TComObjectFactory)
public
procedure UpdateRegistry(Register: Boolean); override;
end;
procedure TShellExComObjectFactory.UpdateRegistry(Register: Boolean);
const
HooksKey = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\ShellExecuteHooks';
var
hKey: HKEY; Status, Disp: Integer; ClassID: string;
begin
ClassID := GUIDToString(Class_TShellExecuteHook);
if Register then begin
Status := RegCreateKeyEx(HKEY_LOCAL_MACHINE, HooksKey, 0, '', REG_OPTION_NON_VOLATILE,
KEY_READ or KEY_WRITE, nil, hKey, @Disp);
if Status = 0 then begin
RegSetValueEx(hKey, PChar(ClassID), 0, REG_SZ, PChar(Description), Length(Description)+1);
RegCloseKey(hKey);
end;
end else begin
Status := RegOpenKeyEx(HKEY_LOCAL_MACHINE, HooksKey, 0, KEY_READ or KEY_WRITE, hKey);
if Status = 0 then begin
RegDeleteValue(hKey, PChar(ClassID));
RegCloseKey(hKey);
end;
end;
if Status <> 0 then raise EOleError.Create('建立註冊表項失敗');
inherited UpdateRegistry(Register);
end;
initialization
TShellExComObjectFactory.Create(ComServer, TTShellExecuteHook, Class_TShellExecuteHook,
'TShellExecuteHook', 'ShellExecute Hook Sample', ciMultiInstance, tmApartment);
ShellExecute/Ex,不保證捕獲所有外殼行為(如右鍵→屬性可能走其他路徑)。