Создание COM-сервера

Всем привет!

Чем отличается программист от другого типа человека разумного?
Я думаю, постоянным желанием подшутить над братом меньшим - Человеком нормальным, благо способов для этого - великое множество. В реестре Windows неограниченное количество мест для автоматического запуска программ - сейчас нас интересует расширение оболочки - контекстное меню Эксплорера. Займемся созданием +СОМ-сервера который будет запускаться при вызове контекстного меню.
Сразу оговорюсь - на компе потенциального испытуемого должна стоять звуковая карта и, желательно, антивирус Касперского, чтобы испытуемому был хорошо известен вопль AVP при обнаружении вируса.

Для начала, создадим файл ресурса содержащего нужный нам вопль.
Создаем текстовый файл, пишем в нем на одной строке:

MYWAVE RCData C:\Temp\Infected.wav


(вместо C:\Temp\Infected.wav пишете реальный путь к *.wav файлу)
Сохраняем файл с именем WAVE.RC. Далее выполняем команду:

brcc32.exe C:\Temp\Wave.rc


(вместо C:\Temp\Wave.rc пишете реальный путь к Wave.rc файлу)
У нас получился файл ресурсов Wave.res который мы будем использовать дальше.

В примерах Delphi есть почти все, что нам нужно:

..:\Program Files\Borland\Delphi7\Demos\ActiveX\ShellExt\ContextM.pas


Немножко редактируем этот файл (в смысле выбрасываем ненужное - добавляем нужное) и получаем примерно это:


unit Unit1;  
  
interface  
  
uses  
  Windows, ActiveX, ComObj, Classes,  
  Dialogs, StdCtrls,  
  ShlObj;  
  
type  
  TInitWormHook = class(TComObject, IShellExtInit, IContextMenu)  
  protected  
    { IShellExtInit }  
    function IShellExtInit.Initialize = SEIInitialize;  
    function SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;  
      hKeyProgID: HKEY): HResult; stdcall;  
    { IContextMenu }  
    function QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst, idCmdLast,  
      uFlags: UINT): HResult; stdcall;  
    function InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult; stdcall;  
    function GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;  
      pszName: LPSTR; cchMax: UINT): HResult; stdcall;  
  end;  
  
  function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult; stdcall;  
  function DllCanUnloadNow: HResult; stdcall;  
  
const  
  Class_ContextMenu: TGUID = '{1A39ADB3-5ED9-44F4-B6BA-5B3D41255033}';  
  
implementation  
  
uses ComServ, SysUtils, ShellApi, Registry, Graphics, mmSystem;  
  
//Цепляем наш ресурс  
{$R wave.res}  
  
function TInitWormHook.SEIInitialize(pidlFolder: PItemIDList; lpdobj: IDataObject;  
  hKeyProgID: HKEY): HResult;  
begin  
  Result := NOERROR;  
end;  
  
function TInitWormHook.QueryContextMenu(Menu: HMENU; indexMenu, idCmdFirst,  
          idCmdLast, uFlags: UINT): HResult;  
begin  
  Result := 0;  
end;  
  
function TInitWormHook.InvokeCommand(var lpici: TCMInvokeCommandInfo): HResult;  
begin  
  Result := NOERROR;  
end;  
  
function TInitWormHook.GetCommandString(idCmd, uType: UINT; pwReserved: PUINT;  
  pszName: LPSTR; cchMax: UINT): HRESULT;  
begin  
  Result := NOERROR;  
end;  
  
type  
  TInitWormHookFactory = class(TComObjectFactory)  
  public  
    procedure UpdateRegistry(Register: Boolean); override;  
  end;  
    
//А это - наша процедура по извлечению звука из файла ресурса  
procedure RUNWAV;  
var  
WaveHandle: THandle;  
  WavePointer: pointer;  
  begin  
  WaveHandle:= FindResource(hInstance, 'MYWAVE', RT_RCDATA);  
  if WaveHandle <> 0 then  
    begin  
      WaveHandle := LoadResource(hInstance, WaveHandle);  
      if WaveHandle <> 0 then  
        begin;  
          WavePointer:= LockResource(WaveHandle);  
          sndPlaySound(WavePointer, snd_Memory or SND_ASYNC);  
          UnlockResource(WaveHandle);  
          FreeResource(WaveHandle);  
        end;  
    end;  
end;  
  
procedure TInitWormHookFactory.UpdateRegistry(Register: Boolean);  
var  
  ClassID: string;  
begin  
  if Register then begin  
    inherited UpdateRegistry(Register);  
    ClassID := GUIDToString(Class_ContextMenu);  
    CreateRegKey('Directory\shellex\ContextMenuHandlers\WAV', '', ClassID);  
    if (Win32Platform = VER_PLATFORM_WIN32_NT) then  
      with TRegistry.Create do  
        try  
          RootKey := HKEY_LOCAL_MACHINE;  
          OpenKey('SOFTWARE\Microsoft\Windows\CurrentVersion\Shell Extensions', True);  
          OpenKey('Approved', True);  
          WriteString(ClassID, 'FTP simple client');  
        finally  
          Free;  
        end;  
  end  
  else begin  
    DeleteRegKey('Directory\shellex\ContextMenuHandlers\WAV');  
    inherited UpdateRegistry(Register);  
  end;  
end;  
  
function DllGetClassObject(const CLSID, IID: TGUID; var Obj): HResult;  
begin  
  Result:=ComServ.DllGetClassObject(CLSID, IID, Obj);  
  if Result = S_OK then begin  
    try  
     RUNWAV;  
    except  
    end;  
  end;  
end;  
  
function DllCanUnloadNow: HResult;  
begin  
  Result := ComServ.DllCanUnloadNow;  
  if Result = S_OK then begin  
    try  
     RUNWAV;  
    except  
    end;  
  end;  
end;  
  
initialization  
  TInitWormHookFactory.Create(ComServer, TInitWormHook, Class_ContextMenu,  
    '', 'FTP simple client', ciMultiInstance,  
    tmApartment);  
end.  
Теперь нам нужно скомпилировать из этого модуля DLL-ку. Пишем проект ShWave.dpr:


library ShWave;  
  
uses  
  ComServ,  
  Unit1 in 'Unit1.pas';  
  
exports  
  DllGetClassObject,  
  DllCanUnloadNow,  
  DllRegisterServer,  
  DllUnregisterServer;  
begin  
end.  

После компиляции получаем ShWave.dll

Мы получили +СОМ-сервер, теперь осталось его подключить к контекстному меню. Пишем файл реестра Install.reg:

REGEDIT4

[HKEY_CLASSES_ROOT\CLSID\{1A39ADB3-5ED9-44F4-B6BA-5B3D41255033}\InprocServer32]
@="ShWave.dll"
"ThreadingModel"="Apartment"

[HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\WAV]
@="{1A39ADB3-5ED9-44F4-B6BA-5B3D41255033}"

[HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers\WAV]
@="{1A39ADB3-5ED9-44F4-B6BA-5B3D41255033}"

Закидываем файл ShWave.dll в %SystemRoot%\System32, запускаем Install.reg и при попытке использования контекстного меню будет звучать вопль AVP или тот, который вы сами зашили в ресурс.

Вместо \*\ можно использовать любое расширение файлов и СОМ-сервер будет активизироваться только при щелчке правой кнопкой мыши на файлах выбранного типа.

Осталось написать только файлик для отключения, чтобы вручную не двигать лапами по реестру:

REGEDIT4
[-HKEY_CLASSES_ROOT\CLSID\{1A39ADB3-5ED9-44F4-B6BA-5B3D41255033}\InprocServer32]
[-HKEY_CLASSES_ROOT\CLSID\{1A39ADB3-5ED9-44F4-B6BA-5B3D41255033}]
[-HKEY_CLASSES_ROOT\*\shellex\ContextMenuHandlers\WAV]
[-HKEY_CLASSES_ROOT\Directory\shellex\ContextMenuHandlers\WAV]


Вот и все.
Теги:
COM-сервер
Добавлено: 07 Августа 2018 21:14:29 Добавил: Андрей Ковальчук Нравится 0
Добавить
Комментарии:
Нету комментариев для вывода...