Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

deleted oneself from disk while running in RAM

23 views
Skip to first unread message

Mark Meyers

unread,
Dec 18, 2000, 5:52:11 PM12/18/00
to
I'm wondering if there's a sure way to have a process running,
c:\foo.exe
that could then delete c:\foo.exe

Which I don;t know of a way to do, so, I want to be able to launch the
process that destroys foo.exe such that foo.exe a) launches the uninstaller
program, and then b) foo.exe shuts down, and then c) the uninstaller program
deletes foo.exe, where, the uninstaller is something like a windows INF
script being run with rundll32. Basically I want to be able to remove every
last trace of foo from the system, and he's the guy that, when running,
knows when it's time to do so.

Any pointers are appreciated.
thx.
-Mark

Carey Gregory

unread,
Dec 18, 2000, 6:12:23 PM12/18/00
to
Have foo.exe launch a detached second process (foo2.exe) and then
terminate. Once it terminates foo2.exe can delete foo.exe.

--
Carey Gregory

Luc Kumps

unread,
Dec 19, 2000, 3:07:58 AM12/19/00
to
Here's something that will work on all Windows versions...

First, write an extra program: "waitmutex.exe".
This program simply waits until the mutex named in the first command line
parameter is released, then sleeps for x seconds (you never know the program
is still running after releasing the mutex), and then exits

In your "real" program, you do this:
1. Create a mutex, and grab it
2. Create a temporary .BAT file, with three lines:
waitmutex whatever_unique_name_you_came_up_with
del waitmutex.exe
del realprog.exe
del %0.bat
3. Start the command processor in a hidden window, and tell it to execute
(with /C) the .BAT file you created.
4. Do whatever your "real" program does
5. Release the mutex
6. Exit

This works on most OS'es (I think):
http://www.microsoft.com/msj/0198/Win320198.htm
Chris King reported this about it (to get it to work on his system):
"However, I found I needed a Sleep() or WaitForInputIdle() after the
CreateProcess() call to allow the second instance to start correctly before
I CloseHandle()'d the first instance.

Luc

"Mark Meyers" <m...@ipass.net> wrote in message
news:O#AHCUUaAHA.1332@tkmsftngp05...

Guillaume Landru

unread,
Dec 19, 2000, 4:19:30 AM12/19/00
to
But then how do you delete foo2.exe? ;)

Cheers,
Guillaume.

"Carey Gregory" <sp...@nugenesis.spam.com> wrote in message
news:7c6t3t4hd1v6ror36...@4ax.com...

Neil J. Rubenking

unread,
Dec 19, 2000, 9:31:46 AM12/19/00
to
In article <O#AHCUUaAHA.1332@tkmsftngp05>, m...@ipass.net says...

> I'm wondering if there's a sure way to have a process running,
> c:\foo.exe
> that could then delete c:\foo.exe
The 'official' technique for deleting an in-use file differs in Win9x-
family and WinNT-family. In the former, you open or create WININIT.INI in
the Windows folder. You must open it as text, not as INI, because it's
not a legitimate INI file - multiple keys with the same name. It would
look like this:

[rename]
nul=c:\snafu\foo.exe
nul=c:\foo\bar.exe

In NT-family, you call MoveFileEx() with a null second argument and the
MOVEFILE_DELAY_UNTIL_REBOOT flag.
--
Neil J. Rubenking
Contributing Technical Editor
PC Magazine

Carey Gregory

unread,
Dec 19, 2000, 11:47:42 AM12/19/00
to
"Guillaume Landru" <to...@titi.net> wrote:

>But then how do you delete foo2.exe? ;)

Hey, he only asked how to delete foo.exe. Please see the cashier on
the way out. ;-)

--
Carey Gregory

Leonid Troyanovsky

unread,
Dec 20, 2000, 4:00:12 AM12/20/00
to

Mark Meyers wrote:

> I'm wondering if there's a sure way to have a process running,
> c:\foo.exe that could then delete c:\foo.exe

It's _NT only_ pascal (Delphi) example.

--
WBR, LVT

--------------------------------------------------------
program Project1;

{$APPTYPE CONSOLE}

uses
windows,
sysutils;

var
StartInfo: TStartupInfo;
ProcInfo: TProcessInformation;
cmdLine: String;
hprocess: THandle;

begin
if ParamStr(1) = '/del' then
begin
hprocess := OpenProcess(PROCESS_ALL_ACCESS, False, StrToInt(ParamStr(2)));
WaitForSingleObject(hprocess, INFINITE);
DeleteFile(PChar(ParamStr(3)));
ExitProcess(0);
end;

CopyFile(PChar(ParamStr(0)), 'tmp.exe', False);

if CreateFile(PChar('tmp.exe'),
GENERIC_READ,
FILE_SHARE_READ,
nil,
OPEN_EXISTING,
FILE_FLAG_DELETE_ON_CLOSE,
0)= INVALID_HANDLE_VALUE then
ExitProcess(1);

cmdline := Format('tmp.exe /del %d "%s"', [GetCurrentProcessID, ParamStr(0)]);
FillChar(StartInfo, SizeOf(StartInfo), 0);
StartInfo.cb:=SizeOf(StartInfo);

if CreateProcess ( nil,
PChar(cmdLine),
nil,
nil,
false,
0,
nil,
nil,
StartInfo,
ProcInfo ) then
begin
CloseHandle(ProcInfo.hThread);
CloseHandle(ProcInfo.hProcess);
Writeln('Press any key for delete..');
Readln;
end
else
ExitProcess(2);
end.

Gary Nebbett

unread,
Dec 20, 2000, 5:58:32 AM12/20/00
to
The appended code is my favourite approach for NT systems; it does not require any additional
files - just insert the code into an existing program.

Gary

#include <windows.h>

int main(int argc, char *argv[])
{
HMODULE module = GetModuleHandle(0);

CHAR buf[MAX_PATH];

GetModuleFileName(module, buf, sizeof buf);

CloseHandle(HANDLE(4));

ULONG p = ULONG(module) + 1;

__asm {
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push p
push DeleteFile
push FreeLibrary
ret
}

return 0;
}

dave porter

unread,
Dec 20, 2000, 9:46:01 AM12/20/00
to
Wow, that HANDLE(4) is breathtaking
in its daring. Howdya know that the
process's main section is always going
to be the first thing opened in
the process?

dave

p.s. Your code seems to lack
error handling :-)

--
To reply by mail, replace 'z' by 's'


"Gary Nebbett" <gary.n...@syngenta.com> wrote in message
news:91q3cn$v8n$1...@novalfsmtp1.novsvcs.net...

gary.n...@syngenta.com

unread,
Dec 20, 2000, 11:14:15 AM12/20/00
to
In article <91qgnb$638$1...@bob.news.rcn.net>,

"dave porter" <por...@mangozoft.com> wrote:
> Wow, that HANDLE(4) is breathtaking
> in its daring. Howdya know that the
> process's main section is always going
> to be the first thing opened in
> the process?
>
> dave
>
> p.s. Your code seems to lack
> error handling :-)

Hello Dave,

The rather cavalier reasoning and observations that led to
the hard-coded value is that when creating a new process,
the first handle that is added to the handle table is that
of the executable image section and there is no user-mode
variable that holds this value (and therefore the handle
will presumably never be closed). This is of course just an
artifact of the implementation.

Never having worked on a safety critical system, I am rather
in the habit of just letting a program crash and then
analysing the remains :-)

Gary


Sent via Deja.com
http://www.deja.com/

Mark Meyers

unread,
Dec 20, 2000, 2:14:35 PM12/20/00
to
Thx.

"Luc Kumps" <NOkum...@pandora.be> wrote in message
news:yHE%5.12797$Ww.2...@afrodite.telenet-ops.be...

Mark Meyers

unread,
Dec 20, 2000, 2:21:58 PM12/20/00
to
int main(int argc, char *argv[])
{
__asm {
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push p
push DeleteFile
push FreeLibrary
ret
}

return 0;
}

What do you get from pushing all those params on the stack before returning-
who reads them?
(Sorry, not an experienced assembly coder)

-Mark

<gary.n...@syngenta.com> wrote in message
news:91qlsd$6hm$1...@nnrp1.deja.com...

Luc Kumps

unread,
Dec 20, 2000, 3:40:29 PM12/20/00
to
When you are in subroutine, the stack contains:
1. The return address
2. The eventual parameters.

When the ginal RET executes, it "returns" to the address on the top of the
stack, which is FreeLibrary.
The FreeLibrary finds these two things on the stack:
1. The address to return to (=DeleteFile)
2. The value of p, which is the parameter passed to FreeLibrary

When FreeLibrary returns, it returns to DeleteFile, which finds on the
stack:

1. Return address=ExitProcess
2. Parameter = eax = address of buf = name of file to delete

When DeleteFile returns, it returns to ExitProcess, which finds on the
stack:
1. Return address 0 (never used)
2. Value 0 (exit code of process)

Luc

"Mark Meyers" <m...@ipass.net> wrote in message

news:e9dnsnraAHA.1852@tkmsftngp02...

dave porter

unread,
Dec 20, 2000, 3:43:32 PM12/20/00
to
"Mark Meyers" <m...@ipass.net> wrote in message
news:e9dnsnraAHA.1852@tkmsftngp02...
> What do you get from pushing all those params on the stack before
returning-
> who reads them?
> (Sorry, not an experienced assembly coder)
>
> -Mark

The 'ret' pops an address from the stack and 'returns'
to it, so it actually calls FreeLibrary. FreeLibrary returns
to DeleteFile, DeleteFile returns to ExitProcess,
ExitProcess doesn't return.

> int main(int argc, char *argv[])
> {
> __asm {
> lea eax, buf

> push 0 // arg for ExitProcess
> push 0 // return from ExitProcess call (not used)
> push eax // arg for DeleteFile
> push ExitProcess // return from DeleteFile call
> push p // arg for FreeLibrary
> push DeleteFile // return from FreeLibrary call
> push FreeLibrary // return from here
> ret
> }
>
> return 0;
> }
>

In other words Gary's caused a sequence of functions
to get called, by setting up the stack, without ever
touching the code section again (which is just as well
since it presumably vanishes half-way through the
sequence).

What a perversion (and I mean that as a compliment :-)

dave

dave porter

unread,
Dec 20, 2000, 3:52:55 PM12/20/00
to
Actually, I do have one question - it seems
you need to CloseHandle -and- FreeLibrary
to get rid of the code section?

So there's something other than handle #4
being open which is keeping the code
around? (I presume FreeLibrary is merely
Win32ese for FreeImageFileSections, there's nothing
particularly libroid about it).

dave

--
To reply by mail, replace 'z' by 's'


"Gary Nebbett" <gary.n...@syngenta.com> wrote in message
news:91q3cn$v8n$1...@novalfsmtp1.novsvcs.net...

dave porter

unread,
Dec 20, 2000, 3:55:45 PM12/20/00
to

"dave porter" <por...@mangozoft.com> wrote in message
news:91r679$6si$1...@bob.news.rcn.net...

> Actually, I do have one question - it seems
> you need to CloseHandle -and- FreeLibrary
> to get rid of the code section?
>
> So there's something other than handle #4
> being open which is keeping the code
> around? (I presume FreeLibrary is merely
> Win32ese for FreeImageFileSections, there's nothing
> particularly libroid about it).
>
> dave


Never mind, I read the Win32 documentation
where it mentions reference counts.

Mark Meyers

unread,
Dec 20, 2000, 6:21:12 PM12/20/00
to
Guys;
I'm running a little behind here. HANDLE(4) ? Is that the handle of the
EXE ?
And to get the p- GetModuleHandle(0) + 1. The EXE handle plus 1?


"dave porter" <por...@mangozoft.com> wrote in message
news:91r679$6si$1...@bob.news.rcn.net...

gary.n...@syngenta.com

unread,
Dec 21, 2000, 4:16:14 AM12/21/00
to
In article <91r679$6si$1...@bob.news.rcn.net>,

"dave porter" <por...@mangozoft.com> wrote:
> Actually, I do have one question - it seems
> you need to CloseHandle -and- FreeLibrary
> to get rid of the code section?
>
> So there's something other than handle #4
> being open which is keeping the code
> around? (I presume FreeLibrary is merely
> Win32ese for FreeImageFileSections, there's nothing
> particularly libroid about it).
>
> dave
>
Hello Dave,

That is an interesting question. If you look at figure 7-24 in
the 3rd edition of Inside Microsoft Windows 2000, there are two
things that keep the whole mesh of data structures (including
the file object for the executable file) alive: the VAD and the
section object. CloseHandle(HANDLE(4)) deletes the section
object and UnmapViewOfFile(module) deletes the VAD.

In the program that I posted, I used FreeLibrary(ULONG(module) +
1) because I had previously observed some undocumented behaviour
of FreeLibrary that caused it to ignore reference counts and
simply unmap a library if the low bit of the module was set. On
reflection, I think that it would be better to use
UnmapViewOfFile directly. Attached is an updated (and slightly
shorter!) version of the program.

Gary

#include <windows.h>

int main(int argc, char *argv[])
{
HMODULE module = GetModuleHandle(0);

CHAR buf[MAX_PATH];

GetModuleFileName(module, buf, sizeof buf);

CloseHandle(HANDLE(4));

__asm {


lea eax, buf
push 0
push 0
push eax
push ExitProcess

push module
push DeleteFile
push UnmapViewOfFile
ret
}

return 0;

Michael Geary

unread,
Jan 27, 2001, 1:17:38 AM1/27/01
to

This is a truly remarkable hack. One of the most clever pieces of code I've
ever seen.

Alas, this and the version posted previously work only on NT/2000. Has
anyone come up with a similar trick for 95/98/Me? If not, maybe I'll give it
a crack when I get some time...

-Mike

<gary.n...@syngenta.com> wrote in message
news:91shos$o3q$1...@nnrp1.deja.com...

george

unread,
Jan 27, 2001, 6:16:58 PM1/27/01
to

> This is a truly remarkable hack. One of the most clever pieces of code I've
> ever seen.

this is indeed dazzling!

on a probably related (ie., DeleteFile after UnmapViewOfFile) topic,
how can one find which process uses some file (to be deleted)? eg.:

| C:\>del /q /s "C:\WINNT\Profiles\george\Temporary Internet Files"
| C:\WINNT\Profiles\george\Temporary Internet
Files\Content.IE5\index.dat
| The process cannot access the file because
| it is being used by another process.

(after, obviously, one exits IE itself -- to purge its 'temp' stuff)
there must be some dll still laying around which *uses* index.dat:
which one?

thanks,
george

Michael Geary

unread,
Jan 28, 2001, 12:12:01 AM1/28/01
to

"george" <-.-@-.-> wrote in message news:3A7356EA.ADE77AC1@-.-...

> on a probably related (ie., DeleteFile after UnmapViewOfFile) topic,
> how can one find which process uses some file (to be deleted)?

Let me take a guess. I'll bet www.sysinternals.com has something for this...

Yup, they do! HandleEx:

http://www.sysinternals.com/ntw2k/freeware/handleex.shtml

-Mike

0 new messages