How can I make my C# app erase itself (self-destruct)? Here's two ways that I think might work:
Supply another program that deletes the main program. How is this deleter program deleted then, though?
Create a process to CMD that waits a few seconds then deletes your file. During those few seconds, you close your application.
Both of those methods seem inefficient. I have a feeling that there's some built-in flag or something in Windows that allows for such stuff. How should I do it? Also, can you provide some sample code?
UPDATE: Thanks for all your answers! I'm going to try them, and see where that gets me.
First of all, some people have asked why I'd want my app to do this. Here's the answer: a few days ago, I read the Project Aardvark spec that Joel Spolsky posted on his blog, and it mentioned that the client app would delete itself after the remote session. I'm wondering how this works, and how, if I ever need to do this, I can accomplish such a feat.
Here's a little overview of what's been suggested:
Create a registry entry that tells Windows to delete the file on reboot
Launch CMD with a ping command to wait a few seconds and then delete the file
Both of those, of course, have their disadvantages, as outlined in the comments.
However, would such a method as outlined below work?
There are two executables: Program.exe and Cleaner.exe. The former is the program itself, the latter is the app that deletes Program.exe and itself (if it's loaded into memory, as I'm about to explain). Is it possible for Program.exe (which has dependencies) to load all of Cleaner.exe, which doesn't have any dependencies, into memory and run it?
If this is possible, could Cleaner.exe be packaged inside Program.exe, loaded into memory, and run?
There's a MoveFileEx API, which, when given a MOVEFILE_DELAY_UNTIL_REBOOT flag, will delete specified file on next system startup.
There's a great CodeProject Article about this topic.
Edit: Basically it's a simple cmd-call which will delete the specified files after some seconds.
Process.Start("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 3000 > Nul & Del " + Application.ExecutablePath);
Application.Exit();
You will never be able to guarantee that this will work, as long as you require a physical presence on the machine. For example:
What if the app fails to release a resource in a timely fashion while you're trying to delete it? An error occurs, and the app remains.
The behavior of one app starting another which then deletes the first app is very suspicious from an AV perspective. You are likely to trigger defenses on a user's machine which may kill the process that's trying to kill your original app.
If you do something like delete a file at reboot, what if the user moves your file in between or makes a copy? It's not in the original spot anymore, and the app remains.
If your application requires this level of security, consider hosting it on a machine you control (e.g., by providing a web service and letting a stub client access it that way).
On a somewhat related note, one is also tempted to speculate about the motives of someone who (1) requires a physical presence on someone's machine and (2) wants to delete the evidence that the app existed.
A correction to #Bobby answer, in case people will find it useful - executable path needs to be quoted. Additionally, below is setting cmd.exe window to be hidden (otherwise it flashes as a black console window) and converted to run without relying on System.Windows.Forms assembly (the Application class).
var exepath = Assembly.GetEntryAssembly().Location;
var info = new ProcessStartInfo("cmd.exe", "/C ping 1.1.1.1 -n 1 -w 3000 > Nul & Del \"" + exepath + "\"");
info.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(info).Dispose();
Environment.Exit(0);
There is also FileOptions.DeleteOnClose, but that requires the file to be open for writing. You might be able to do it with a sequence like this (untested):
Program launches as Original.exe, and detects (from its own name) that it needs to trigger the self-destruct function.
Original.exe creates a new file Temp.exe with FileOptions.DeleteOnClose and copies its own content into it, but does not close it yet
Original.exe opens a second, read-only handle to Temp.exe and closes the first write handle. The read-only handle can co-exist with an execute handle, whilst keeping the file open to delay auto-deletion.
Original.exe launches Temp.exe. Temp.exe detects that it has been launched from the temp directory and bypasses the self-destruct sequence and continues normal operation.
Original.exe exits (taking its read-only handle to Temp.exe with it.)
Temp.exe continues running. When it exits, the file Temp.exe will no longer be in use so it will be deleted automatically.
Edit #2: Actually I don't think this is possible, because it relies on the kernel opening the file with the FILE_SHARE_DELETE flag, which is unlikely.
sorted by NJ
c#
the other codes does not work so its simple
if u create bath file that loops to del application and
the batch file itself
u can use takkill command to kill the process if u dont want to use
application.close method
`string delname = "test.cmd";
string fileurl = Application.ExecutablePath;
System.IO.StreamWriter file = new System.IO.StreamWriter(delname);
file.WriteLine(":Repeat");
file.WriteLine("del \"" + fileurl + "\"");
file.WriteLine("if exist \"" + fileurl + "\" goto Repeat");
file.WriteLine("del \"" + delname + "\"");
file.Close();
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.FileName = delname;
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
Process.Start(startInfo);`
`
Th3 3e3 one is not 3d parts ov one
I5
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Think CMD
int sectosleep = 5000;
string exename = "yourexe.exe";
string location = #"c:\yourexe.exe"
Process.Start("cmd.exe", "/C taskkill /f /im " + exename + " & ping 1.1.1.1 -n 1 -w " + sectosleep + " > Nul & Del /F /Q \"" + location + "\"");
;>
I know reflector deletes itself if you use an old version and choose not to update. You might try to figure out what it does. I would start with FileMon and see if it spawns any processes to achieve this.
Since my application (a Windows Service) is installed via the Windows Installer, I self-delete using this:
Dim uninstall_params As String = "/x {MY-PRODUCTS-GUID} /qn /norestart REBOOT=ReallySuppress"
proc.StartInfo = New ProcessStartInfo("msiexec.exe", uninstall_params)
proc.Start()
Environment.Exit(-1)
Sorry--it's in VB, but it should be easily convertible to C#.
Works in Windows 7 & 8, **ENSURE you run your application with admin privileges or you will get an error.
This code exists elsewhere so I can't take full credit I found I made it work for me by adding "Application.Exit();"
static void autodelete()
{
string batchCommands = string.Empty;
string exeFileName = Assembly.GetExecutingAssembly().CodeBase.Replace("file:///", string.Empty).Replace("/", "\\");
batchCommands += "#ECHO OFF\n"; // Do not show any output
batchCommands += "ping 127.0.0.1 > nul\n"; // Wait approximately 4 seconds (so that the process is already terminated)
batchCommands += "echo j | del /F "; // Delete the executeable
batchCommands += exeFileName + "\n";
batchCommands += "echo j | del deleteMyProgram.bat"; // Delete this bat file
File.WriteAllText("deleteMyProgram.bat", batchCommands);
Process.Start("deleteMyProgram.bat");
Application.Exit();
}
This is the Uninstall.exe:
Shutdown.
Wait for 3 sec.
Try to kill that task if it is still running.
Wait for 3 sec.
Delete the app directory with the Uninstall.exe in it.
public void Uninstall()
{
var delPath = AppDomain.CurrentDomain.BaseDirectory;
var procId = Process.GetCurrentProcess().Id;
var psi = new ProcessStartInfo
{
FileName = "cmd.exe",
Arguments = $"/C timeout 3 & Taskkill /F /PID {procId} & timeout 3 & rd /s /q \"{delPath}\"",
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
};
Process.Start(psi);
Application.Current.Shutdown();
}
Related
Hi I'm trying to convert either a doc or docx to a pdf in a c# MVC application. I know I can do this using libreOffice. So I created a simple batch file to take 2 variables and then run them into the libreoffice 'soffice' headless to convert to pdf.
So that gave me this code.
echo on
SET var1=%2
IF "%var1:~-1%"=="\" SET var1=%var1:~0,-1%
cd "C:\Program Files\LibreOffice 5\program\"
soffice --headless --convert-to pdf %1 --outdir %var1%
Originally I thought the problem was within my MVC application and the way I called this batch script. But I commented (REM) the soffice and outputted out the command in the bash using the standard output.
var psi = new ProcessStartInfo("cmd.exe", "/k " + command);
//psi.CreateNoWindow = true;
psi.FileName = command;
psi.UseShellExecute = false;
psi.RedirectStandardError = true;
psi.RedirectStandardOutput = true;
psi.Arguments = string.Format("{0} {1}", fullPath2, tempPath);
var process = Process.Start(psi);
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
Trace.WriteLine(output);
Trace.WriteLine(error);
process.WaitForExit();
When I commented the soffice line - it hit the WaitForExit and worked no problems (ok with no pdf conversions, but the script exited).
If I don't do that it seems to execute the cmd and even the soffice commands because I can see them in the task manager - but obvisouly nothing happens.
Additionally the code above works when I did a c# command line program (I've hard coded the file/command lines in both instances). The executable also works when I run as the user that is running the app pool in my MVC application.
The bash file also works file 'standalone' no matter if me or my appPool user run it.
So what gives - why won't this run.
This is the code that comes out of that trace - so what the bash script does.
c:\windows\system32\inetsrv>echo on
c:\windows\system32\inetsrv>SET var1=C:\inetpub\xxxxxxxxx\Temp\
c:\windows\system32\inetsrv>IF "\" == "\" SET var1=C:\inetpub\xxxxxxxxx\Temp
c:\windows\system32\inetsrv>cd "C:\Program Files\LibreOffice 5\program\"
C:\Program Files\LibreOffice 5\program>soffice --headless --convert-to pdf C:\inetpub\xxxxxxxxx\Temp\636295920370843147.doc --outdir C:\inetpub\xxxxxxxxx\Temp
I've got a feeling that this has something to do with the amount of characters or something because the soffice does fireup (can see it in the task manager).
FYI there are no spaces or special characters anywhere.
Any ideas?
Update
This looks to be an issue with the wait command. So any help with that helpful, I'm starting to think perhaps this is an issue with c# and libreoffice 5 - I've seen examples that supposedly work with libreoffice 4.
I guess my challenge continues....
I have an issue with an auto update software that I am trying to make. The application runs as a server application and checks via FTP for updates and downloads them if there is a newer version available. This then unzips a folder called update in the programs root directory. it then launches a file called update.bat that does any file copying etc that I may need to do for that update. Once this is finished the update.bat launches the new server application. Once the program goes to check for updates again it is suppose to delete the update directory that is in the root directory of the server application as well as the update.rar file that was downloaded from the update server. All of this works perfectly except the folder is being used and will not delete. I have read all kinds of things about releasing the handle and changing the current directory etc.. but just can't seem to get it to work. I would appreciate someone helping me out here. Here is the code for this update.
private void Form1_Load(object sender, EventArgs e)
{
foreach (string s in Directory.GetDirectories("C:/my update dir"))
{
if (s.Contains("Instance"))
{
var _instance = Regex.Match(s, #"\d+");
Process p = new Process();
ProcessStartInfo pinfo = new ProcessStartInfo();
pinfo.FileName = "cmd.exe";
pinfo.WorkingDirectory = "C:/mySQL/bin";
pinfo.Arguments = "/C mysql.exe -u** -p** dbnameHere" + _instance.ToString() +
" < \"C:/my update dir/update/update.sql\"";
p.StartInfo = pinfo;
p.Start();
p.WaitForExit();
p.Close();
p.Dispose();
Directory.SetCurrentDirectory("C:/");
}
}
Directory.SetCurrentDirectory("C:/");
this.Dispose();
Application.Exit();
}
I'm going to guess that your problem is here:
Once this is finished the update.bat launches the new server
application.
Windows is going to "lock" the directories all the way down to the .BAT file. So if the .BAT runs a server process from that directory, that process is going to inherit the CWD and file descriptors of the calling process.
It's not clear from your code that this is what's happening, but you may also want to try changing the CWD prior to spawning the process.
no error. no exception. Second and Third produce a file f[1]/[2]. but not first. why? I verify using debug that the command is good. and using the command I capture from debug , cut and past to command line, I can produce the file[f0].
string[] f = new string[4];
f[0] = "SNICKER.reg.txt";
f[1] = "SNDIS.reg.txt";
f[2] = "SNICS.reg.txt";
f[3] = "Ssmf.xml";
//First
Run_Process("REG", "EXPORT HKEY_LOCAL_MACHINE\\SOFTWARE\\sridge\\Snicker " + f[0] + " /y");
//Second
Run_Process("REG", "EXPORT HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\services\\SNDIS " + f[1] + " /y");
//Third
Run_Process("REG", "EXPORT HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control\\SClass " + f[2] + " /y");
private static void Run_Process(string exe_name, string arg)
{
Process myProcess = new Process();
try
{
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.FileName = exe_name;
//myProcess.StartInfo.Arguments = "/C getLH.exe > feed.txt";
myProcess.StartInfo.Arguments = arg;
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
myProcess.WaitForExit();
}
catch (Exception ep)
{
Console.WriteLine(exe_name + " " + arg + ". Error: " + ep.Message);
}
}
When your app runs on a 64bit OS and you try to access the registry you could end up reading the values in the wrong folders.
This happens when you compile for x86 Platform, and thus your code is emitted as 32bit code.
In this scenario the registry redirector kicks in and changes your hand made registry paths that point to folders inside HKLM\SOFTWARE to HKLM\SOFTWARE\Wow6432Node.
The reasoning behind this behavior is complex and you could try to read something here
Said that, I still cannot understand really well what happen when we put in this scenario the REG program executed as a process launched from an application built with AnyCPU. This application should be executed as a 64bit code but, for some reason, the REG program executed is the 32 bit version (yes, there are two version of REG.EXE, one in system32 and one in SysWow64) and this version search your data in the wrong path. Perhaps this is related to the current value of the PATH environment variable.
As a side note. One of the worst decision ever made by Microsoft is to allow applications to store their configuration data in the registry. I really suggest to change this behavior, if possible
UPDATE
I can confirm that on a 64bit OS, a console application compiled as AnyCPU running the code that executes the REG.EXE command as above launches the 32bit version of REG.EXE from the WINDOWS\SYSWOW64. I have checked with ProcMon and I cannot explain why this happens. It is not related to the PATH env variable because I have only the path to C:\WINDOWS\SYSTEM32
Check out Process.start: how to get the output? and try to use that method to see the output of your command. I don't think there will be any exception, because it will only catch the exception of that block of code, not the exception of outside program that you attempt to run.
I'm trying to copy a file over to a networked folder on a mapped drive. I tested out COPY in my command line which worked, so I thought I'd try automating the process within C#.
ProcessStartInfo PInfo;
Process P;
PInfo = new ProcessStartInfo("COPY \"" + "c:\\test\\test.txt" + "\" \"" + "w:\\test\\what.txt" + "\"", #"/Z");
PInfo.CreateNoWindow = false; //nowindow
PInfo.UseShellExecute = true; //use shell
P = Process.Start(PInfo);
P.WaitForExit(5000); //give it some time to finish
P.Close();
Raises an exception : System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
What am I missing? Would I have to add anything else to the command parameters?
I've tried File.Copy but it doesn't appear to work (File.Exists("<mappeddriveletter>:\\folder\\file.txt");) brings up false.
This SO post contains an example
Run Command Prompt Commands
how to do it right. You need to call cmd.exe with /c copy as a parameter.
Well, for the technical bit: copy in itself is not an executable, but merely a command interpreted by cmd. So basically, you'd have to start cmd.exe as a process, and pass it a flag that makes it run the copy command (which you'll also have to supply as a parameter).
Anyways, I'd side with Promit and recommend looking into File.Copy or something similar.
e: Ah, missed your comment on Promit's answer when I posted this.
Wouldn't it be a lot easier to use File.Copy ?
I capture audio files in the wave format in my Microsoft Surface application. Now for file size reasons, I'd like to convert the wave file into a mp3 file. I read in the Internet that a good possibility to do that is using lame.
But how can I call this exe file from my application? and how can I include it into my application?
Use Process class to call an external application:
string lameEXE = #"C:\path_of_lame\lame.exe";
string lameArgs = "-V2";
string wavFile = #"C:\my_wavs\input.wav";
string mp3File = #"C:\my_mp3s\output.mp3";
Process process = new Process();
process.StartInfo = new ProcessStartInfo();
process.StartInfo.FileName = lameEXE;
process.StartInfo.Arguments = string.Format(
"{0} {1} {2}",
lameArgs,
wavFile,
mp3File);
process.Start();
process.WaitForExit();
int exitCode = process.ExitCode;
You can call an executable from .NET by using the System.Diagnostics.Process class and related classes - see here for the documentation.
Lame has pretty robust command line arguments, which can be found here. You can pass command line arguments to the Process using the ProcessStartInfo.Arguments property.
public void mciConvertWavMP3(string fileName, bool waitFlag)
{
//maxLen is in ms (1000 = 1 second)
string outfile= "-b 32 --resample 22.05 -m m \"" + pworkingDir+fileName + "\" \"" + pworkingDir + fileName.Replace(".wav",".mp3") + "\"";
System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
psi.FileName = "\"" + pworkingDir + "lame.exe" + "\"";
psi.Arguments = outfile;
//psi.WorkingDirectory = pworkingDir;
psi.WindowStyle = System.Diagnostics.ProcessWindowStyle.Minimized;
System.Diagnostics.Process p = System.Diagnostics.Process.Start(psi);
if (waitFlag)
{
p.WaitForExit();
// wait for exit of called application
}
}
Above code taken from here .
Depending on the usage, you can incorporate a Process.StartInfo object, control properties such as ShellExecute and also redirect any output from the application to (say) a log file or UI component.
To bundle the exe with your project, check this question from stackoverflow out. Personally, I'd go with the first suggestions:
There are several ways you could
accomplish this. First, you should add
program.exe to the project. You would
do this by right-clicking the project
in Visual Studio, and selecting Add >
Existing Item... Select program.exe,
and it will appear in the project.
Viewing its properties, you can set
"Copy to Output Directory" to "Copy
Always", and it will appear in your
output directory beside your
application.
If you stick to the above method, then reference lame.exe relatively ('....\Tools\Lame.exe' for example).
Finally, according to the official lame site : RareWares offers several compiled LAME versions, including modified versions featuring special functionality.
There is a DLL version of LAME, I would be surprised if you can't find a VB or C# example using it. Check this discussion thread: http://www.eggheadcafe.com/software/aspnet/31294459/-lameencdll-and-vbnet.aspx