Click to See Complete Forum and Search --> : Application Delete Itself?


Chambers
July 21st, 2003, 12:05 PM
Could anyone give a useful hand on deleting a program that is running? To be more precise I am executing a program that I want to delete itself, I have currently implemented a .bat file method which keeps trying to delete the exe until the app exits (frees the virtual memory allocation) and deletes the file followed by the .bat itself. However, :) the when the app creates the .bat and attempts to execute it, virus software can pick it up as a 'virus' which is undesirable. I am told there is a way to unload the exe from the virtual memory space so I am free to delete it, anyone know what it is?

MikeP
July 28th, 2003, 03:23 PM
Are you asking how to delete the hard disk image of application that is currently running from within that same appolication? If you are then I have a solution: Windows does not allow you to delete the file on disk of a program which has been loaded into memory. To delete it I used another running process. I created a remote thread inside another process, which would erase my application. Right after starting that remote, my process exits. Remote thread waits for a couple of seconds while my appliation unloads and then deletes the file from disk.

filthy_mcnasty
July 28th, 2003, 09:20 PM
MikeP, i like the way you think =)

that's a pretty good solution to a problem i've seen frequently and heard a lot of rubbish answers to. unfortunately it's not the easiest thing in the world to actually do unless you know the basics of a DLL and process relationships and are running on a newer OS (it's possible on win9x too but is so much harder that books dont even describe it)

the only problem is that your dll then has no way of unloading until the other process closes, which isn't really too bad if you do it right but this can be seen as a bad thing anyways.

MikeP
July 29th, 2003, 09:21 AM
Hey,
Yeah you speak the truth, the dll cannot unload itself and will be in the process memory until the process is killed. The way i recently did it is without any dll. I used VirtualAllocEx to allocate some memory in the remote process and then copied the code into that area. Then I used CreateRemoteThread with that memory pointer as a starting function. That does however leave an extra page of memory in the process (4096 bytes), but is not really noticable and does not cause any problems. If you are interested I can send you some code that I wrote recently which works under Window NT 4.0. Take care.

filthy_mcnasty
July 29th, 2003, 11:49 AM
I am interested in seeing that if you dont mind. The only way I've ever done is using VirtualAllocEx to allocate some memory in the other process then WriteProcessMemory to put info in the other process and CreateRemoteThread as you said to basically force the other process to call LoadLibrary on a dll of my choice. to copy code as you say i haven't done and interested to see exactly what you did.

MikeP
July 29th, 2003, 12:08 PM
This code uses the standard windows Calculator program to delete itself from disk. The remote thread sleeps for 3 second to let the application close before proceeding. This could also be achieved using synchronization objects, but would require more code to implement. Notice that I actually allocated two memory blocks in the remote process, one for code and one for data. This could all be combined into one: first write the argument into the memory location, and then write the code into the same memory page only in offset equal to the lenght of argument (sizeof(Commong))



#include <windows.h>
#include <conio.h>
#include <stdio.h>

typedef struct {
FARPROC DelFile;
TCHAR fileName[100]; //filename to delete, set to your application
FARPROC sleep;
} Common;

DWORD __stdcall F(Common * c)
{
((VOID(__stdcall*)(DWORD))c->sleep)(3000); //let your app close
((BOOL(__stdcall*)(LPCSTR))c->DelFile)(c->fileName);
return 0;
}

void main()
{
HWND hwnd = FindWindow(NULL, "Calculator");
if (!hwnd) {printf("no window\n"); return; }
DWORD id;
GetWindowThreadProcessId(hwnd, &id);

HANDLE hp = OpenProcess(PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION |
PROCESS_VM_READ |
PROCESS_VM_WRITE,
FALSE, id );

if (!hp) {printf("no process\n"); getch(); return;}

LPVOID lpFunc = VirtualAllocEx(hp, NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

DWORD nw;
WriteProcessMemory(hp, lpFunc, (LPVOID)&F, 4096, &nw);

LPVOID lpData = VirtualAllocEx(hp, NULL, 1024, MEM_COMMIT, PAGE_READWRITE);

Common c;
HINSTANCE lib = LoadLibrary("KERNEL32.dll");
c.sleep = GetProcAddress(lib, "Sleep");
c.DelFile = GetProcAddress(lib, "DeleteFileA");
FreeLibrary(lib);
//set this to your application path to delete it
//this also could be retrieved dynamically using API's
lstrcpy(c.fileName, "C:\\Program Files\\DevStudio\\MyProjects\\InsertCode\\Debug\\InsertCode.exe");
WriteProcessMemory(hp, lpData, (LPVOID)&c, sizeof(c), &nw);

DWORD tid;
HANDLE hThread;
hThread = CreateRemoteThread(hp, NULL, 0,
(LPTHREAD_START_ROUTINE)lpFunc, lpData, 0, &tid);
CloseHandle(hp);
return;
}

filthy_mcnasty
July 29th, 2003, 01:03 PM
pretty nifty code. i can tell you've been doing this stuff for awhile. ;) everything i have done of the sort has just been with the method i described, getting the address of LoadLibrary and making the other process run my dll.

dlls offer more flexibility with what you can do in the other process (pretty unlimited really) but
as far as having an application delete itself, your way is much better considering it doesn't require another file to actually do the work. kudos on the excellent code.

joscollin
November 3rd, 2003, 07:28 AM
Originally posted by filthy_mcnasty
pretty nifty code. i can tell you've been doing this stuff for awhile. ;) everything i have done of the sort has just been with the method i described, getting the address of LoadLibrary and making the other process run my dll.

dlls offer more flexibility with what you can do in the other process (pretty unlimited really) but
as far as having an application delete itself, your way is much better considering it doesn't require another file to actually do the work. kudos on the excellent code.

Hi filthy,

I did this as a sample program. It works good.
But In my project it shows runtime error while creating
remote thread.

I have implemented this in WinMain of my project.
The following is the code:
The mainHandle semaphore is released in WM_CLOSE.

Pls reply...
collin.
-----------------------------------------------------------------
// Client.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "ConnectionMgr.h"
#include <stdio.h>

typedef struct
{
FARPROC slp;
FARPROC DelClient;
char fName[MAX_PATH]; //client file Name

} Common;

DWORD __stdcall Block(Common* c)
{
((VOID(__stdcall*)(DWORD))c->slp)(3000);
((BOOL(__stdcall*)(LPCSTR))c->DelClient)(c->fName);
return 0;
}

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// TODO: Place code here.
HANDLE mainHandle;
mainHandle = CreateSemaphore(NULL,0,1,NULL);

CConnectionMgr *m_pConnectionMgr = new CConnectionMgr(hInstance,16,mainHandle, lpCmdLine);

m_pConnectionMgr->start();
WaitForSingleObject(mainHandle,INFINITE);
delete m_pConnectionMgr;

//code for Self Delete
// Program Manager's virtual address space is used for writing
// the Code for Deletion.
HWND hPMWnd = FindWindow(NULL, "Program Manager");
if(!hPMWnd) return 0;

DWORD pid;
GetWindowThreadProcessId(hPMWnd, &pid);
HANDLE hProcess = OpenProcess(PROCESS_CREATE_THREAD |
PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
FALSE, pid);
if(!hProcess) return 0;

LPVOID lpBlock = VirtualAllocEx(hProcess, NULL, 4096, MEM_COMMIT, PAGE_EXECUTE_READWRITE);

DWORD bWritten;//writing Block to address space of Program Manager
WriteProcessMemory(hProcess, lpBlock, (LPVOID) &Block, 4096, &bWritten);

LPVOID lpData = VirtualAllocEx(hProcess, NULL, 1024, MEM_COMMIT, PAGE_READWRITE);

Common c;
//call functions in Block to initialize c
HMODULE hMod = LoadLibrary("kernel32.dll");
c.slp = GetProcAddress(hMod, "Sleep");
c.DelClient = GetProcAddress(hMod, "DeleteFileA");
FreeLibrary(hMod);

if(GetModuleFileName(NULL, c.fName, MAX_PATH))
WriteProcessMemory(hProcess, lpData, (LPVOID)&c, sizeof(c), &bWritten);

DWORD thId;
HANDLE hThread;
hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpBlock,
lpData , 0, &thId);
CloseHandle(hProcess);


return 0;
}

------------------------------------------------

filthy_mcnasty
November 3rd, 2003, 09:24 AM
i have to go to work (so i'll look at it more closely later) but looking at it quickly i think the problem is with Program Manager.


change
HWND hPMWnd = FindWindow(NULL, "Program Manager");

to
HWND hPMWnd = FindWindow("Shell_TrayWnd", NULL);

i think that's the main cause of your runtime error.
if you wait to create the thread until your program closes anyways then there is no need for the semaphore. i used a mutex so that i could invoke the self delete function and the program continues to run then when it closes the mutex becomes signaled and the delete function can kill the application.

fransn
November 3rd, 2003, 01:46 PM
Ok Thanks you very much.
These are the kind of posts you might want to delete/not share, it's too cool.

filthy_mcnasty
November 3rd, 2003, 03:40 PM
and it has a lot of implications fransn. a similiar method can be used to make a program copy itself (i shouldn't have to explain why this is relevant) or move itself around.

i'm tenative to share my approach to this but mikep's way is definately a good starting ground.

i also agree that it's very cool but since this thread started i still find myself using my forementioned method of "simple" dll injection more frequently. then i dont have to worry about multiple writeprocessmemory/virtualallocex calls and i can let my own process run it's work.

to not share it on the basis that you need some experience to understand it is one thing but to not share stuff like this on the basis that it's "too cool" i dont really agree with. i like to spread the wealth.

anyways, joscollin, as mentioned i think the main problem with your sample there is that you've chosen ProgramManager to create a remote thread in and some processes (that being one of them) simply dont like it when you do that. windows explorer is another one that behaves the same way. that's why i use the Shell_traywnd (the clock) cuz it's always present and doesn't have this problem. try that and if you still have problems just holler.


annnd, to spread the wealth (per say).... anyone interested in this topic (which is extremely powerful when you boil it down) should see chapter 22 of "Programming Applications for Microsoft Windows" by Jeffrey Richter. he doesn't touch the win9x way of doing this (because doing so is largely undocumented for it, and it's much more complicated) but it's a good read nonetheless.
it's a good book on the whole too.

joscollin
November 4th, 2003, 12:44 AM
Originally posted by filthy_mcnasty
and it has a lot of implications fransn. a similiar method can be used to make a program copy itself (i shouldn't have to explain why this is relevant) or move itself around.

i'm tenative to share my approach to this but mikep's way is definately a good starting ground.

i also agree that it's very cool but since this thread started i still find myself using my forementioned method of "simple" dll injection more frequently. then i dont have to worry about multiple writeprocessmemory/virtualallocex calls and i can let my own process run it's work.

to not share it on the basis that you need some experience to understand it is one thing but to not share stuff like this on the basis that it's "too cool" i dont really agree with. i like to spread the wealth.

anyways, joscollin, as mentioned i think the main problem with your sample there is that you've chosen ProgramManager to create a remote thread in and some processes (that being one of them) simply dont like it when you do that. windows explorer is another one that behaves the same way. that's why i use the Shell_traywnd (the clock) cuz it's always present and doesn't have this problem. try that and if you still have problems just holler.


annnd, to spread the wealth (per say).... anyone interested in this topic (which is extremely powerful when you boil it down) should see chapter 22 of "Programming Applications for Microsoft Windows" by Jeffrey Richter. he doesn't touch the win9x way of doing this (because doing so is largely undocumented for it, and it's much more complicated) but it's a good read nonetheless.
it's a good book on the whole too.

Same problem with Shell_TrayWnd.
It shows run time error only in this program.
There are somany threads starting in my program and
CConnectionMgr is one of them. This may be the cause.

fransn
November 4th, 2003, 05:43 AM
Try FindWindow("Progman", 0);

what I meant with not readily sharing too much. It could take days of investigating a topic like this and to me the IT world is competitive enough to justify keeping the hard-to-figure-out code to yourself. I'm not saying it for my sake.
But please keep it coming if you feel like it.

joscollin
November 4th, 2003, 06:06 AM
Originally posted by fransn
Try FindWindow("Progman", 0);

what I meant with not readily sharing too much. It could take days of investigating a topic like this and to me the IT world is competitive enough to justify keeping the hard-to-figure-out code to yourself. I'm not saying it for my sake.
But please keep it coming if you feel like it.

I got the same runtime error

filthy_mcnasty
November 4th, 2003, 10:52 AM
you're right fransn, i will hardly ever simply post this sort of code but i do not have a problem with helping others with it. joscollin what you're doing looks ok. must have something funky going on behind the scenes there.
if you'd like, upload the project and i'll take a look at it more closely.

filthy_mcnasty
November 4th, 2003, 03:39 PM
ok so i tinkered with my own program that does this and found that using even Progman works. i managed to confuse myself over which ones worked and which didnt. it was the desktop window that was failing.

obtained either by
hwndRemote = FindWindow("#32769", NULL);
or
hwndRemote = GetDesktopWindow();

both failed. point being, the problem with your code is almost definately something going on in one of those threads or something I'm just looking over.

i should reitterate though, that as your code currently stands you still do not need the semaphore. simply call that stuff directly from wm_close or something.
the point i was making with mutex/semaphore talk is so that i can call my selfdelete function and it creates a mutex that isn't destroyed until my program exits and the code copied into the OTHER process waits on this event.


((DWORD(__stdcall*)(HANDLE, DWORD))lpcd->wait)(lpcd->handle, INFINITE); // WaitForSingleObject(hMutex, INFINITE);
((BOOL(__stdcall*)(HANDLE))lpcd->close)(lpcd->handle); // CloseHandle(hMutex);
((BOOL(__stdcall*)(LPCSTR))lpcd->DelFile)(lpcd->szFileName); //DeleteFile(lpcd->szFileName);


these are the first 3 lines of what i "copy" into the other process, you can see the changes i made to the original. i obviously changed the structure itself too but maybe i'm just rambling now. lemme know if you still want help.