locked
Creating Process: CreateProcess vs .NET Process; Former fails to work correctly RRS feed

  • Question

  • Hi all,


    I'm trying to instrument compiler processes from various compilers. My current approach is to write a simple proxy executable, replace (in case of VC) cl.exe with my proxy, and make my proxy call the original cl.exe. To get more detailed information, I'm injecting a custom DLL which intercepts the CreateFileW function. Now, the DLL injection works fine. It's the starting of the original process that I'm struggling with at the moment.

    My proxy executable is written in C# and it uses EasyHook (an OSS, Detours-like library) to inject the DLL.
    My first attempt was to start the original cl.exe using the System.Diagnostics.Process class. As far as starting the original compiler process was concerned, this actually worked like a charm. However, with this approach, there exists a delay between process creation and DLL injection. Because of this delay I miss valuable information, or in more extreme cases: the DLL gets injected when the compiler process is already done and shut down.
    The code for this attempt is displayed below:
    Process process = new Process();
    
    ProcessStartInfo startInfo = process.StartInfo;
    startInfo.UseShellExecute = false;
    startInfo.RedirectStandardError = true;
    startInfo.RedirectStandardOutput = true;
    startInfo.FileName = FullExePath;
    startInfo.Arguments = InCommandLine;
    startInfo.CreateNoWindow = true;
    
    process.Start();
    
    // Inject DLL here
    RemoteHooking.Inject(… // ..snip

    My second attempt uses the RemoteHooking.CreateAndInject() method from EasyHook. What this method does is call CreateProcessW with the CREATE_SUSPENDED flag, after which it can inject the DLL before any code in the new process is ran, which is exactly what I'm after. The C code that creates the suspended process is displayed below. The CustomFlags is something I pass from my managed code.
    CustomFlags  = CREATE_NO_WINDOW;
    
    STARTUPINFO		StartInfo;
    PROCESS_INFORMATION	ProcessInfo;
    
    // ..snip..
    
    // create suspended process
    StartInfo.cb = sizeof(StartInfo);
    StartInfo.wShowWindow = TRUE;
    
    CreateProcessW(
    	FullExePath, 
    	InCommandLine, 
            NULL, NULL,  
            FALSE, 
    	CustomFlags | CREATE_SUSPENDED,
    	NULL,
    	CurrentDir,
    	&StartInfo,
    	&ProcessInfo);

    The process gets started, and my DLL gets injected. However, when using my proxy in the compiler process, compilation fails. Because I/O isn't redirected (not possible with CreateAndInject in EasyHook at the moment), I don't get any error messages to help me out. My guess is it doesn't have to do with the fact that I/O isn't redirected, because in my example with System.Diagnostics.Process, not redirecting I/O doesn't affect the compilation process at all, and everything still works.
    My current theory is that there is a difference in the way .NET's Process class creates a new process, and the way I'm currently using CreateProcessW. So, what I'm looking for is the exact way how System.Diagnostics.Process creates a new process behind the scenes, or some brilliant insights that I'm currently missing.

    Any help and insights in how I can make my second approach work would be greatly appreciated.


    Cheers,


    Jurriën



    P.S. Would CurrentDir have anything to do with it?
    P.P.S. It would be great if System.Diagnostics.Process would support creating a suspended process....

    • Edited by J. Stutterheim Saturday, March 13, 2010 3:24 PM Formatting Code Snippets
    Saturday, March 13, 2010 3:22 PM

All replies

  • Sorry, I got lost on the last part of exactly what isn't working.  I have a lot of experience with Detours type technology, but not EasyHook.

    You can see exactly how Process works if you use a utility like NetMassDownloader to download the .NET source code.

    You will find everything you need when you download in:
    .\dd\ndp\fx\src\Services\Monitoring\system\Diagnosticts\Process.cs

    Saturday, March 13, 2010 7:31 PM
  • Hi Eric,


    Thanks! That looks like it might give me the info I need. I will try it out as soon as I get back to my dev machine.

    Just to recap my problem for the record in a slightly shorter format ;)

    Compilation succeeds:
    MSBuild -(calls cl.exe)-> Proxy cl.exe w/ System.Diagnostics.Process -> original cl.exe

    Compilation fails:
    MSBuild -(calls cl.exe)-> Proxy cl.exe w/ "manual" CreateProcessW call (in EasyHook) -> original cl.exe

    The problem is that I'm not sure how the process instantiation is different between the two approaches. So, why does the former approach work fine, while the latter fails?


    Cheers,


    Jurriën
    Sunday, March 14, 2010 8:11 AM
  • It appears that System.Diagnostics.Process always calls CreateProcess() using only the lpCommandLine argument, and it always passes NULL to lpApplicationName. Also, both security attributes are always set to NULL, and bInheritHandles is always set to TRUE.
    Hopefully this will solve my problem tomorrow when I get to my dev machine :)
    Sunday, March 14, 2010 4:23 PM
  • Did that fix your problem?
    Wednesday, March 17, 2010 12:11 AM