views:

147

answers:

1

I need to recognize and fire an event when a file is going to be executed or run by an application. I know I can do it by hooking windows procedures, but I don't know what procedure or event of windows fires. For example, when an autorun file going to execute, my application should recognize it, Like an antivirus application.

I'm not sure that hooking is useful for my purpose, if solution isn't hooking, please give me a true solution.

+9  A: 

try using the PsSetCreateProcessNotifyRoutine, this function adds a driver-supplied callback routine to, or removes it from, a list of routines to be called whenever a process is created or deleted.

you can find a very nice sample int this link written in c++

Detecting Windows NT/2K process execution

UPDATE

Another option is use the WMI events, check the Win32_Process class, the ExecNotificationQuery method and the SWbemEventSource.NextEvent function.

Check this sample tested in delphi 7 and Windows 7, you must run this application from outside of the Delphi IDE or disable the exception notification for the EOleException exception (check this link), to avoid the EOleException wich is intercepted by the IDE.

program GetWMI_InstanceCreationEvent;

{$APPTYPE CONSOLE}

uses
  SysUtils
  ,Windows
  ,ComObj
  ,ActiveX
  ,Variants;


Function KeyPressed:boolean; //detect if an key is pressed
var
NumEvents   : DWORD;
ir          : _INPUT_RECORD;
bufcount    : DWORD;
StdIn       : THandle;
begin
Result:=false;
StdIn := GetStdHandle(STD_INPUT_HANDLE);
NumEvents:=0;
GetNumberOfConsoleInputEvents(StdIn,NumEvents);
    if NumEvents<> 0 then
    begin
        PeekConsoleInput(StdIn,ir,1,bufcount);
        if bufcount <> 0 then
        begin
            if ir.EventType = KEY_EVENT then
            begin
              if ir.Event.KeyEvent.bKeyDown then
              result:=true
              else
              FlushConsoleInputBuffer(StdIn);
            end
            else
            FlushConsoleInputBuffer(StdIn);
        end;
    end;
end;


function VarStrNUll(VarStr:OleVariant):string;//dummy function to handle null variants
begin
  Result:='';
  if not VarIsNull(VarStr) then
  Result:=VarToStr(VarStr);
end;

function GetWMIObject(const objectName: String): IDispatch; //create a wmi object instance
var
  chEaten: Integer;
  BindCtx: IBindCtx;
  Moniker: IMoniker;
begin
  OleCheck(CreateBindCtx(0, bindCtx));
  OleCheck(MkParseDisplayName(BindCtx, StringToOleStr(objectName), chEaten, Moniker));
  OleCheck(Moniker.BindToObject(BindCtx, nil, IDispatch, Result));
end;

Procedure  GetWin32_InstanceCreationEvent;
var
  objWMIService              : OLEVariant;
  colMonitoredProcesses      : OLEVariant;
  objLatestProcess           : OLEVariant;
begin
  objWMIService := GetWMIObject('winmgmts:\\localhost\root\cimv2');
  colMonitoredProcesses      := objWMIService.ExecNotificationQuery('Select * From __InstanceCreationEvent Within 1 Where TargetInstance ISA ''Win32_Process'''); //Get the event listener
  while not KeyPressed do
  begin
    try
     objLatestProcess := colMonitoredProcesses.NextEvent(100);//set the max time to wait (ms)
    except
     on E:EOleException do
     if EOleException(E).ErrorCode=HRESULT($80043001) then //Check for the timeout error wbemErrTimedOut 0x80043001
     objLatestProcess:=Null
     else
     raise;
    end;

    if not VarIsNull(objLatestProcess) then
    begin
      Writeln('Process Started '+VarStrNUll(objLatestProcess.TargetInstance.Name));
      Writeln('CommandLine     '+VarStrNUll(objLatestProcess.TargetInstance.CommandLine));
      Writeln('PID             '+VarStrNUll(objLatestProcess.TargetInstance.ProcessID));
    end;
  end;
end;



begin
 try    
    CoInitialize(nil);
    try
      Writeln('Press Any key to exit');
      GetWin32_InstanceCreationEvent;
    finally
    CoUninitialize;
    end;

 except
    on E:Exception do
    Begin
        Writeln(E.Classname, ': ', E.Message);
        Readln;
    End;
  end;
end.
RRUZ
thanks a lot PRUZit`s very useful , but there is a question !when an autorun file ( Autorun.inf ) attempting to execute a command or run a file , we can get the process executed address but how can i get the autorun file address ?In other word , I want to get the address of the Process and the object that executed the process ...thanks a lot ...
Mahmood_N
@Mahmood_N, check this link http://msdn.microsoft.com/en-us/library/aa394372%28VS.85%29.aspx to see all the properties wich you can use, the `ParentProcessId` returns the PID of the parent process. when you get the pid you can retrieve any info using the Windows API or the WMI itself.
RRUZ
Thanks a lot , That`s what I wanted , best Regards ...
Mahmood_N