Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Windows: Delete EXE after execution

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.

like image 653
0x90 Avatar asked Mar 31 '15 07:03

0x90


Video Answer


2 Answers

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.

like image 200
Orace Avatar answered Oct 21 '22 11:10

Orace


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.

like image 34
shA.t Avatar answered Oct 21 '22 10:10

shA.t