5

I am working on an application in C# which does the following things:

  1. Write an EXE to disk
  2. Execute the EXE through Process.Start()

I am now trying to ensure that the EXE will be deleted once it is closed. The easiest way to do so is to set the FileOptions.DeleteOnClose parameter when creating the EXE using File.Create.

However, this means that the EXE can not be executed while is in use. Once the file handle is closed, the EXE is immediately deleted before it can be executed.

Is there any way to retain a "weak reference" to the EXE in my application which does not lock the file and allows it to be executed? Alternatively, is there any way to unlock the EXE for execution with the file handle still open? Are there any other obvious solutions I am missing?

CLARIFICATION A: I am aware of other methods to delete files in use which will delete the file eventually (e.g. upon reboot). I am however looking for a method to delete the file immediately once it starts executing which is handled by the OS (e.g. when running a batch that first executes the file and then deletes it, the file would remain on disk if the batch job is terminated).

CLARIFICATION B: To explain the bigger picture: The application receives and decrypts an executable file. After decryption, the file should be executed. However, I want to make sure the decrypted version of the EXE does not stay on disk. Ideally, I also want to prevent users from copying the decrypted EXE. However, since the decryption application runs as the same user, this will be impossible to achieve in a truly secure fashion as both have the same privileges on the system.

shA.t
  • 16,580
  • 5
  • 54
  • 111
0x90
  • 6,079
  • 2
  • 36
  • 55
  • I disagree. My use of DeleteOnClose actually comes from the article linked to in that particular question's top rated answer. MoveFileEx will delete the file eventually (i.e. upon reboot), not immediately after closing it. I therefore consider this question a specific followup question to one of the answers to the question you link to. – 0x90 Mar 31 '15 at 07:24
  • What you are trying to achieve can not be done using `Fileoptions.DeleteOnClose` because no programfile can be executed while it is opened by another process for writing. (I could tell you why, but it does nothing with the topic, and there is not enough room in a comment for that.) I'm afraid you have to do it in three steps: Write -> Start -> Delete. – mg30rg Mar 31 '15 at 07:34
  • 1
    Hmm. That sounds like a bad idea. What are you actually trying to do? – Luaan Mar 31 '15 at 08:02
  • 1
    You could not write it to disk in the first place and execute it from memory – James Mar 31 '15 at 08:18
  • Luaan -> I have added a clarification. – 0x90 Mar 31 '15 at 12:33
  • 1
    James Barrass -> How would I do that? If I map the exe into the decryption's memory and jump to it, all the addresses will be invalid. I could use reflection if the decrypted EXE is a .NET assembly, but even that turns tricky quickly when dependencies are added in. Any specific technique you can recommend? – 0x90 Mar 31 '15 at 12:35
  • Can you use two file handles? One for the write plus a read only handle. Close the write handle, start executing the process, close the RO handle. – josh poley Apr 02 '15 at 15:52
  • 2
    Where's the non-malicious use case? – Loren Pechtel Apr 02 '15 at 16:24
  • Just wondering.. what forbid someone from saving the memory which contain the execution as file in general? I think you should think carefully if your "breakthrough" really achieve what you aim for.. – G.Y Apr 02 '15 at 16:24
  • josh poley -> That sounds interesting. Can you provide more information, preferably in the form of an answer? – 0x90 Apr 03 '15 at 07:37
  • Loren Pechtel -> Copy Protection. If I were to write malware using this methodology, I'd design it to run without external libraries, load it into memory and jump EIP to it's location. Problem is, we are trying to protect EXEs from other people from being copied so they have dependencies and this won't work. – 0x90 Apr 03 '15 at 07:38
  • G.Y. -> Nothing. Ultimately, all copy protection that has to run on hardware the user controls can and will be broken. I'm just trying to make it a little bit harder. – 0x90 Apr 03 '15 at 07:39

2 Answers2

8

You could use Process.WaitForExit:

var process = Process.Start(processPath);
process.WaitForExit();

// File.Delete(processPath); // Not strong enough (thanks to Binary Worrier)
DeleteOrDie(processPath);    // Will attempts anything to delete the file.

But it gives the possibility to copy the exe from where you writed it.

A good solution is to run it from memory.

If your target exe is a CLR program, you can use the Assembly.Load function:

// read the file and put data in bin
...
Assembly a = Assembly.Load(bin);
MethodInfo method = a.EntryPoint;
if (method == null) throw new NoEntryPointException();
object o = a.CreateInstance(method.Name);
method.Invoke(o, null);

More details here.

If you want to load/execute any exe in memory, you could use the Nebbett’s Shuttle approach but you will need to code it in C/C++ and make a call to it from C#.

Also it looks like Microsoft doesn't like it (security issues) and I don't think you can achieve it from C# only. Good anti-virus will probably detect it.

Orace
  • 7,822
  • 30
  • 45
  • +1: Wrapping the `File.Delete` in an _catch/wait 10ms/retry_ loop might be necessary if there is a delay between the process terminating and windows closing the file. – Binary Worrier Apr 02 '15 at 15:39
  • Nice, that is a reasonable answer. Thank you. The WaitForExit() method would leave the EXE on disk if the calling process is killed during execution, but still. / Unfortunately, we are not only targeting CLR programs, but Nebbett's shuttle may be a workable option. I'll leave the question open for a bit longer to see what else may come in. – 0x90 Apr 03 '15 at 07:43
2

In a not very good way but a way that can give you what you want, I suggest this solution:
(I use a Console Application with some input arguments for this solution)

[1: ] Write a function to check opened processes:

/// <summary>
/// Check application is running by the name of its process ("processName").
/// </summary>
static bool IsProcessOpen(string processName)
{
    foreach (Processing.Process clsProcess in Processing.Process.GetProcesses())
    {
        if (clsProcess.ProcessName.ToUpper().Contains(processName.ToUpper()))
                return true;
    }
    return false;
}

[2: ] Define some variables:

static bool IamRunning = true; 
static int checkDuration = 1;     // in seconds

[3: ] Use a Thread for run a loop for checking:

Thread t = new Thread(delegate() {
    DateTime lastCheck = DateTime.MinValue;
    while (IamRunning)
    {
        var now = DateTime.Now;
        int dd = (now.Hour - lastCheck.Hour) * 3600 + (now.Minute - lastCheck.Minute) * 60 + now.Second - lastCheck.Second;
        if (dd >= checkDuration)
            if (!IsProcessOpen("ProcessName"))
            {
                delApplication();  // You have a function to delete ...
                break;
            }
    }
});
t.SetApartmentState(ApartmentState.STA);
t.Start();

[4: ] Use a loop at the end of the program:

while (t.ThreadState == ThreadState.Running)
{
    // just wait.
}

Note: This solution by Console Application in my low computer have 50% usage of CPU.

shA.t
  • 16,580
  • 5
  • 54
  • 111
  • You have 50% (100% on one of your two CPU) of usage because you have an infinite loop with no `Thread.Sleep` in it. Furthermore, using it will avoid your (badly coded) DateTime difference computation (just use `(DateTime.Now.Hour - lastCheck).Second`). And you forget to do `lastCheck = now;`. – Orace Apr 08 '15 at 11:19
  • @Orace Thanks, And I ask a [question](http://stackoverflow.com/q/29530946/4519059) about that ;). – shA.t Apr 09 '15 at 06:35