views:

93

answers:

4

I have a legacy application that looks for files in a directory. It does not handle missing files very well. What I want to do is "capture" the file not found errors, and send another file back to the calling app instead. Similar to how you could handle a 404 error on a webserver and return something based on what the requested URL was, except on the local file system.

Is this possible? And more preferably, is it possible in .Net?

+1  A: 

Yes what you described is possible.

I would suggest using a filesystem filter driver or mini filter for this type of thing though which can't be done in .Net.

The way I am suggesting is probably the most proper way that catches everything at the filesystem level.

Brian R. Bondy
would I at least be able to invoke it from .Net?
Neil N
The code would be in C or C++ and then you could pass the info up from there maybe via a registered callback or by some other IPC communication means.
Brian R. Bondy
@Brian R. Bondy. You're wrong. This is totally possible even in .NET
Max
@Max: If you want to catch EVERYTHING you should do it at the filesystem level. This is not possible with .Net.
Brian R. Bondy
@Brian: If by "EVERYTHING" you mean system function, then I can't think of any other Win API functions that the simple application can use for opening a file. Do you have some particular function in mind? And what do you mean by filesystem layer? File system has lots of layers. FS drivers being one of them
Max
@Max: I mean the FS driver layer. By everything I mean any function at all that opens a file. For example I don't know about how fopen is implemented and I'm sure there are others.
Brian R. Bondy
@Max: I reworded again though to more clearly indicate that I mean the way I'm suggesting is not possible in .Net but other ways are possible in .Net.
Brian R. Bondy
fopen isn't a WinAPI function. It's a C library function. fopen calls CreateFile eventually.
Max
@Max: I didn't claim fopen was a win32 api function. The OP didn't ask specifically about only catching Win32 API functions. The op simply said that he wants to catch file not found errors. Are you sure fopen calls CreateFile? Can you show me where this is documented? Are you sure it does that on every version of Windows? Or even on any? By the way I did remove any trace from my answer that discourages other possibilities to accomplish this.
Brian R. Bondy
I asked which Win API functions are used for file openning besides CreateFile and you mentioned fopen. There's no need to intercept all library functions, you can simply intercept the function that these libraries eventually call. In this case it's a CreateFile function. It works in ALL Windows versions. It's very old and very basic function. Here's the docs: http://msdn.microsoft.com/en-us/library/aa363858%28VS.85%29.aspx. You can make sure that it is called in your particular compiler by creating a simple application with fopen and stepping through it in the debugger (ASM view)
Max
@Max: I am aware that you asked for Win API, but I don't know why you asked only for Win32 API calls. The OP didn't state any such requirement in his question. In fact there are no indications about how his legacy application is written. I don't see where it's documented in that link that fopen and all other methods will call CreateFile. I am very aware of the documentation for CreateFile and know it well.
Brian R. Bondy
Because Win API is the intermediate layer between libraries and operating system components. In this case file system. This link of course cannot have any documentation on fopen and "other methods", because fopen is a C library function.
Max
@Max: "This link of course cannot have any documentation on fopen..." Right which is why the link doesn't answer my request.
Brian R. Bondy
@Brian If by request you mean you request to provide a link where is written that no other function can open a file, then your request is irrelevant. I didn't say that there are no other API functions that can open the file. If there are any, then they can also be intercepted with dll injection. This is as if I would ask you, how can you be sure that ALL the programs' file operations can be intercepted with the method you are advising.
Max
@Max: OK cheers.
Brian R. Bondy
+2  A: 

You can do this by intercepting the call to Win API function CreateFile. This requires dll injection. In .NET you can use this library: easyhook.codeplex.com

Max
Every file is eventually opened with CreateFile. Why is it a bad advice? I've tried this library myself some time ago and it works fine.
Max
Every file is not eventually opened with CreateFile.
Brian R. Bondy
Writing a system driver would be a much more complicated task.
Max
@Max: Agree it is much more complex. I guess it depends on if the OP wants to do it the proper way or in a hackish way. Depending on his needs your way would be faster but less proper.
Brian R. Bondy
Maybe there are other Win API functions that open the file (can you name them?), but if there are such functions, then you canm intercept them too. No big deal.
Max
I don't see how injecting dll is an improper way. Lots of software products uses this technique.
Max
Easy Hook looks to be exactly what I was looking for, why would it be considered "Hackish" ?
Neil N
One problem with EasyHook, though, is that to debug your injected dll you need to attach to the process, that you are injecting into. What I did it to place a Debug.Break(); before the code part that I needed to debug and then the target process would show the attach-debugger-dialog. But I guess this is still much more convenient than writing a system driver.
Max
A: 

If a commercial solution is acceptable, then something like Eldos CallbackFilter might fit the bill:

http://www.eldos.com/cbflt/spec.php

I haven't used it for exactly your purposes, but you can certainly intercept file system calls, where you could check if the file exists and create a dummy one if none exists.

This might prove to be a lot more straightforward for sorting out a badly behaving legacy application.

chibacity
+1  A: 

If you know where the code in the process that is going to open the file, you could write a wrapper process around it that acts like a debugger, intercept the call, check to see if it exists yourself, and if not, replace the filename with a different one.

Something like:

CreateProcess(bla bla, DEBUG_ONLY_THIS_PROCESS, bla bla);

SetBreakPoint(address of code to set breakpoint)
{
  ReadProcessMemory to save off byte for breakpoint
  WriteProcessMemory 0xCC to set breakpoint
  FlushInstructionCache
}

while (TRUE == bContinue)
{
  bContinue = WaitForDebugEvent(&debugEvent);
  switch (dwDebugEventCode)
  {
    case EXCEPTION_BREAKPOINT:
      // Read the file name from memory, check if it exists, if not, replace it with
      // new file name using the same length in memory :)
      // Replace your code byte you read out when you set the breakpoint
  }
}

Another method is to overwrite the function call table with your own call to CreateFile (or whatever they are using in the app in question). Look up API hooking, or even Dll injection may help you out here.

Microsoft has the Detours package that can help you out, and CodePlex has the EasyHook that looks quite interesting.

GalacticJello