Hooking CreateProcess with CreateAndInject causes problems

Feb 26, 2010 at 2:01 PM

Hi all,

 

I've been working with EasyHook the past week, and it has been mostly great so far! It has made some of my goals really easy to accomplish. However, there is one thing that I'm struggling with.

I'm trying to hook my custom DLL into every child process of Visual Studio (devenv.exe), so that it can instrument the compilation process. So far, I have been half successful. I have two possible solutions at the moment. Both work from within an intercepted CreateProcess call.

The first one intercepts CreateProcess, manually calls the original CreateProcess function, and then injects the DLL. This works, although I am not receiving any feedback from the injected DLL. Also, because the process is already started when I inject the DLL, there is a chance that I'm missing some valuable information from the process. Pasted below is the code for this attempt:

 

static bool CreateProcess_Hooked(
    string lpApplicationName,
    string lpCommandLine,
    IntPtr lpProcessAttributes,
    IntPtr lpThreatAttributes,
    bool bInheritHandles,
    int dwCreationFlags,
    IntPtr lpEnvironment,
    string lpCurrentDirectory,
    ref STARTUPINFO lpStartupInfo,
    out PROCESS_INFORMATION lpProcessInformation)
{
    lpProcessInformation = new PROCESS_INFORMATION();
    int ProcessId = 0;
                           
    try
    {
        DemoInjection This = (DemoInjection)HookRuntimeInfo.Callback;

        const int CREATE_SUSPENDED = 0x00000004;
        dwCreationFlags = CREATE_SUSPENDED;
        DidCreateProcess = CreateProcess(
            lpApplicationName,
            lpCommandLine,
            lpProcessAttributes,
            lpThreatAttributes,
            bInheritHandles,
            dwCreationFlags | (int)CreationFlags.CREATE_SUSPENDED,
            lpEnvironment,
            lpCurrentDirectory,
            ref lpStartupInfo,
            out lpProcessInformation);
        /**
         * This approach works, but there is still the chance of a race condition, seeing as
         * the DLL is injected after the process has started. The CREATE_SUSPENDED flag doesn't seem to do much.
         * Also, it doesn't seem to capture the results of the compilation from the child processes.
         */
        This.Interface.AddHookedProcess(lpProcessInformation.dwProcessId);

        RemoteHooking.Inject(
            lpProcessInformation.dwProcessId,
            "ProcMonInject.dll",
            "ProcMonInject.dll",
            This.ChannelName);

lock (This.Queue) { if (This.Queue.Count < 1000) { This.Queue.Push("App: " + lpApplicationName + " Com: " + lpCommandLine); } } } catch (Exception e) { MessageBox.Show(e.Message); } return true; }

 

My second attempt uses RemoteHooking.CreateAndInject(). The nice thing about this solution is that it will give me precious information right from the start. However, I seem to have troubles to make the process work. When injecting my DLL in the Visual Studio instance, the entire compilation process breaks. Also, it spawns heaps of command windows, that disappear right after. The error in the log window reads: "error PRJ0047 : Could not resume the suspended process.  The build has failed.". However, I am actually calling RemoteHooking.WakeUpProcess() in my Run() method. The code for my hook method and Run() method are pasted below:

 

static bool CreateProcess_Hooked(
    string lpApplicationName,
    string lpCommandLine,
    IntPtr lpProcessAttributes,
    IntPtr lpThreatAttributes,
    bool bInheritHandles,
    int dwCreationFlags,
    IntPtr lpEnvironment,
    string lpCurrentDirectory,
    ref STARTUPINFO lpStartupInfo,
    out PROCESS_INFORMATION lpProcessInformation)
{
    bool DidCreateProcess = false;

    lpProcessInformation = new PROCESS_INFORMATION();
    int ProcessId = 0;
                           
    try
    {
        DemoInjection This = (DemoInjection)HookRuntimeInfo.Callback;

        // VS gives an error when trying to compile:
        // 101>Project : error PRJ0047 : Could not resume the suspended process.  The build has failed.
        // Also, heaps of popup CLI windows appear and disappear, slowing things down significantly.
        RemoteHooking.CreateAndInject(
            lpApplicationName,
            lpCommandLine,
            dwCreationFlags | (int)CreationFlags.CREATE_NO_WINDOW,
            "ProcMonInject.dll",
            "ProcMonInject.dll",
            out ProcessId,
            This.ChannelName);
        lpProcessInformation.dwProcessId = ProcessId;
        // Experimentation with the trusty MessageBox showed that
        // the processes are actually spawned and PIDs are available here.
        // Perhaps things will work when the lpProcessInformation is filled with more data?
        // The chance of that is not very likely though...
        // it works with the regular Inject just fine..
        //MessageBox.Show(Convert.ToString(ProcessId));
        DidCreateProcess = ProcessId != 0;

        lock (This.Queue)
        {
            if (This.Queue.Count < 1000)
            {
                This.Queue.Push("App: " + lpApplicationName + " Com: " + lpCommandLine);
            }
        }
    }
    catch (Exception e)
    {
        MessageBox.Show(e.Message);
    }

    return DidCreateProcess;
}

And the run method:

 

 

public void Run(
    RemoteHooking.IContext InContext,
    String InArg1)
{
    try
    {
        CreateFileHook = LocalHook.Create(
            LocalHook.GetProcAddress("kernel32.dll", "CreateFileW"),
            new DCreateFile(CreateFile_Hooked),
            this);

        CreateFileHook.ThreadACL.SetExclusiveACL(new Int32[1]);

        CreateProcessHook = LocalHook.Create(
            LocalHook.GetProcAddress("kernel32.dll", "CreateProcessW"),
            new DCreateProcess(CreateProcess_Hooked),
            this);

        CreateProcessHook.ThreadACL.SetExclusiveACL(new Int32[1]);
        
        /**
         * If the DLL has been injected using CreateAndInject(),
         * this next line will wake the target process up and run it.
         */
        RemoteHooking.WakeUpProcess();
    }
    catch (Exception e)
    {
        /*
            Now we should notice our host process about this error...
         */
        Interface.ReportError(RemoteHooking.GetCurrentProcessId(), e);

        return;
    }
    // snip...
}

I would very much like my approach with RemoteHooking.CreateAndInject to work, seeing as that will get me the best results. Can anyone see what I am currently doing wrong? Help would be much appreciated!

 

Cheers,

 

Jurriën

 

 

Mar 1, 2010 at 1:27 PM

A quick followup: it seems that  the executables I'm trying to inject my DLL into are _NOT_ managed, so the known issue with managed code does not apply in my situation.

Also another quick question: why is CreateProcessW in thread.c being called with bInherithandles = false?