请问怎么删除程序自己本身?

vo__ov 2006-02-06 09:59:14
请问一下怎么可以删除程序本身?程序正在运行,打开了HANDLE,杀不死 -_-b
我想要他自杀,但是不退出 好像要解除IMAGE在内存的映射什么的~~~请问要怎么弄?
...全文
506 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
vo__ov 2006-02-09
  • 打赏
  • 举报
回复
C语言的不会会看 555555555 ~~~~~~但还是谢谢喇!
chenhui530 2006-02-08
  • 打赏
  • 举报
回复
怎么不行啊
Form_Unload 里加如下面代码
shell "批处理名称",vbhide
end
jilu_sun 2006-02-08
  • 打赏
  • 举报
回复
学习
熊孩子开学喽 2006-02-08
  • 打赏
  • 举报
回复
看到这种问题,一来收藏,二来蹭分,呵呵
WuYunpeng 2006-02-07
  • 打赏
  • 举报
回复
这样好象不行吧!程序没有退出好象就死循环了。
最重要是用完对象要释放其内存
kmlxk0 2006-02-07
  • 打赏
  • 举报
回复
相当的高深啊。。。佩服·~!
chenhui530 2006-02-07
  • 打赏
  • 举报
回复
批处理我是这样写的

start:
del /q ""你的程序名完整路径在本目录不需要指定路径""
if not exist "你的程序名完整路径在本目录不需要指定路径" exit
if exist "你的程序名完整路径在本目录不需要指定路径" goto start
rainstormmaster 2006-02-06
  • 打赏
  • 举报
回复
看看这个,号称可以:
' UPDATED:
' - I now show you how to copy some data between your original process and your hijacked one.
' - How to delete your original program and keep running the code inside (the main point of this code)
' - How to display whole user interfaces and subclass them using your hijacked process (Only an API form for now...but I'll make it better)
' - How to inject in Explorer.exe

http://www.1javastreet.com/vb/scripts/ShowZip.asp?lngWId=1&lngCodeId=45195&strZipAccessCode=tp%2FD451952505
IamDeane 2006-02-06
  • 打赏
  • 举报
回复
我看还是BAT方法比较简单啊
呵呵
rainstormmaster 2006-02-06
  • 打赏
  • 举报
回复
大致的就这么几种方法,你看看哪段代码可以改成vb代码,就自己改吧
rainstormmaster 2006-02-06
  • 打赏
  • 举报
回复
//方法5

By 小林
From http://blog.csdn.net/i_like_cpp/archive/2004/11/27/195888.aspx

DOS虚拟机下的自删除
这个方法乃好友“抑郁天使”所提供的(感谢!),代码如下:
#include
int main(int argc,char *argv[])
{
unlink(argv[0]);
return 0;
}
unlink相信学 C语言的朋友比较熟悉吧,就是删除指定文件,使用TC2.0把上面代码编译为dos下16位的程序,执行看看,是不是在闪出一个dos 窗口后,程序不见啦?!

我们再把上面的程序改写一下,使其可以接受参数:
#include
int main(int argc,char *argv[])
{
sleep(1); //休眠1秒
if(argc==2)
unlink(argv[1]); //删除程序(参数一)
unlink(argv[0]); //删除自身
return 0;
}

通过对其反汇编分析,结合测试,这个自删除的原因应该为DOS下的程序在Windows下是通过虚拟机执行[Win2000下为16位MS-DOS子系统(NTVDM CPU)ntvdm.exe,Win98下应该是Winoa386.mod]的,而当DOS程序在虚拟机下执行时,因为已被虚拟机读入内存,也相当于是解释执行的(类似脚本的执行),所以当DOS程序加载后系统并没有对其进行保护,所以可以在执行中被删除,你可以用如下方法来验证!
使用DEBUG建立一个死循环的DOS下的COM程序,命令如下:
debug
-a
0B22:0100 jmp 100
0B22:0102
-r cx
CX 0000
:02
-n dos16.com
-w
Writing 00002 bytes
-q

运行生成的dos16.com,会产生一个DOS窗口,你手工删除dos16.com下,成功没?^*^
上面的C代码生成的程序太大,用起来麻烦,给你来个汇编的,同样采用DEBUG生成:
-a
0B22:0100 mov si,120
0B22:0103 mov dx,si
0B22:0105 mov ax,4301
0B22:0108 xor cx,cx
0B22:010A int 21
0B22:010C mov ah,41
0B22:010E int 21
0B22:0110 cmp al,5
0B22:0112 je 103
0B22:0114 lodsb
0B22:0115 or al,al
0B22:0117 jne 114
0B22:0119 cmp byte ptr [si],0
0B22:011C jne 103
0B22:011E int 20
0B22:0120 db 'kill.com',0
0B22:0129 db 'selfkill.exe',0,0
0B22:0137
-r cx
CX 0000
:37
-n kill.com
-w
Writing 00037 bytes
-q

上面代码就是调用DOS中断INT 21 的41号功能删除自身的,至于Windows下的应用程序如何使用此方法删除自身的完整代码见[selfkill-dos.asm]文件,和批处理的利用方式一样以隐蔽运行方式调用!

其它方法,本人不推荐使用

By 小林
From http://blog.csdn.net/i_like_cpp/archive/2004/11/27/195888.aspx
rainstormmaster 2006-02-06
  • 打赏
  • 举报
回复
//方法4

By 小林
From http://blog.csdn.net/i_like_cpp/archive/2004/11/27/195888.aspx

远程线程插入自删除
远程线程插入如今广泛用于木马和病毒的自我保护及隐蔽自身,同样我们也可以把它用在程序的自删除。

其中所插入的删除自身的远程线程的代码如下:
KREMOTE_CODE_START equ this byte
call @F
@@:
pop ebx
sub ebx,offset @B ;线程代码重定位
push 500
call [ebx+_lpselfkillSleep] ;休眠0.5秒
lea eax,[ebx+offset _selfkillselfname]
push eax
call [ebx+_lpselfkillDeleteFile] ;删除程序文件
ret

_lpselfkillSleep dd?; Sleep的硬编码地址
_lpselfkillDeleteFile dd?; DeleteFile的硬编码地址
_selfkillselfname: ; 程序自身文件名,主程序内生成写入

KREMOTE_CODE_END equ this byte
KREMOTE_CODE_LENGTH equ offset KREMOTE_CODE_END - offset KREMOTE_CODE_START

主程序中使用GetProcAddress来获取Sleep和DeleteFile的硬编码地址后写入上面,并用GetModuleFileName获取自身路径存入_selfkillselfname处,供远程线程使用。

Win9x下的用于在KERNEL32.DLL中建立远程线程代码如下:
Kernel32 db"KERNEL32.DLL",0
SzCreateKernelThread db 'CreateKernelThread',0
_RemoteCode9Xproc@_RmCodeStart,@_RmCodeLen
local lpThreadID
local lpCreateKernelThread
local hProcess
invoke GetModuleHandle,addr Kernel32
mov ebx,eax
invoke GetProcAddress,ebx,offset szCreateKernelThread
mov lpCreateKernelThread,eax ;取得CreateKernelThread的地址
; _findProcess是一个根据名称查找进程PID的函数过程,详细代码见[selfkill-R9x.asm]
invoke _findProcess,offset Kernel32 ;查找KERNEL32.DLL进程
.if eax
invoke OpenProcess,PROCESS_ALL_ACCESS,TRUE,eax
mov hProcess,eax
invoke WriteProcessMemory,eax,80001100h,@_RmCodeStart,@_RmCodeLen,NULL
.if eax
xor eax,eax
lea ecx,lpThreadID
push ecx
push eax
push eax
push 80001100h
push eax
push eax
call lpCreateKernelThread ;创建KERNEL32.DLL线程
.endif
invokeCloseHandle,hProcess
.endif
ret
_RemoteCode9Xendp
函数的调用格式为:
push KREMOTE_CODE_LENGTH+MAX_PATH ;代码长度
push offset REMOTE_CODE ;代码地址
call _RemoteCode9X
[注意:这里不使用
invoke _RemoteCode9X,offset REMOTE_CODE,KREMOTE_CODE_LENGTH+MAX_PATH
来调用函数,因为我测试时发现invoke调用会使KREMOTE_CODE_LENGTH+MAX_PATH的值变大!也许是编译器的一个BUG?]

在_RemoteCode9X中首先使用GetProcAddress获得CreateKernelThread这个用于在KERNEL32.DLL中建立远程线程的API地址[CreateKernelThread的参数和CreateThread类似,但有一点不同为lpStartAddress参数(线程开始执行的地址)处于KERNEL32.DLL进程中!],然后调用_findProcess过程查找KERNEL32.DLL进程的PID,随后以全部的权限打开此进程,并用WriteProcessMemory把代码写入到KERNEL32.DLL进程80001100h开始的空间内[之所以选择80001100h是因为此处有大段可能未使用得内存00h,这样就不用像中国黑客那样进入0环啦!],最后调用CreateKernelThread创建KERNEL32.DLL线程来删除自身!(Win9x下的远程线程插入自删除完整代码见selfkill-R9x.asm!)


Win2K/XP下的用于建立远程线程的代码如下:
;用于在explorer.exe进程中插入远程线程
szDesktopClassdb'Progman',0
szDesktopWindowdb'Program Manager',0
_RemoteCode2KXPproc @_RmCodeStart,@_RmCodeLen
local @hRmCodeMemory
local @hselfkillProcessID
local @hselfkillProcess
;查找文件管理器窗口并获取进程ID,然后打开进程
invoke FindWindow,addr szDesktopClass , addr szDesktopWindow
lea ecx , @hselfkillProcessID
invoke GetWindowThreadProcessId , eax,ecx
invoke OpenProcess, PROCESS_CREATE_THREAD or PROCESS_VM_OPERATION or PROCESS_VM_WRITE , FALSE , @hselfkillProcessID
mov @hselfkillProcess , eax
;在进程中分配空间并将写入远程代码,建立远程线程
invoke VirtualAllocEx , @hselfkillProcess , NULL , @_RmCodeLen , MEM_COMMIT , PAGE_EXECUTE_READWRITE
.ifeax
mov@hRmCodeMemory,eax
invoke WriteProcessMemory,@hselfkillProcess,eax,@_RmCodeStart,@_RmCodeLen,NULL
xor eax,eax
invokeCreateRemoteThread,@hselfkillProcess,eax,eax,@hRmCodeMemory,eax,eax,eax
invokeCloseHandle,eax
.endif
invokeCloseHandle,@hselfkillProcess
ret
_RemoteCode2KXPendp
函数的调用格式和_RemoteCode9X相同!

上面的函数_RemoteCode2KXP首先调用FindWindow和GetWindowThreadProcessId来获得explorer.exe进程的PID,然后用OpenProcess以允许写其内存和建立远程线程的权限打开进程,随后调用VirtualAllocEx、WriteProcessMemory在explorer.exe申请内存写入代码,最后使用CreateRemoteThread建立远程线程并运行。(Win2K/XP下的远程线程插入自删除完整代码见selfkill-Rnt.asm!)

rainstormmaster 2006-02-06
  • 打赏
  • 举报
回复
方法3:

http://www.codeguru.com/win32/SelfDel.html

Introduction
SelfDelete() is a simple Win API function for creating a self-deleting executable. It works by invoking the command shell as a serialized process to delete the program file.

The Command Shell
The command shell program is defined by the environment variable "COMSPEC". This varies with the Windows OS: Win9x/ME use COMMAND.COM, while WinNT/2K/XP use CMD.EXE. The following string is passed to the command shell:

/c del Filename > nul
which translates to: "Run a single command to delete a file and redirect the output to nowhere." Filename is the full path and name of the file we want to delete. This name needs to be converted into its short 8.3 name to change any extended characters into OEM equivalents.

The command shell is started as an independent process by calling the ShellExecuteEx() function. Its process handle is defined by the SHELLEXECUTEINFO struct member "hProcess". NOTE: The "/c" switch is necessary for the command shell process to exit. Do not omit it from the parameters string.

Serializing Processes
Self-deletion presents us with a special problem: The main program must exit and close its opened file handle before the command shell deletes the file. To do this, we must serialize two independent, parallel processes—the current program process and the command shell process. This is done by manipulating CPU resource priorities to temporarily suppress the command shell process. As written, the code will allocate all CPU resources to the main program until it exits. This effectively blocks any command shell execution until the program has terminated.

CPU Allocation
Allocating the REALTIME_PRIORITY_CLASS and THREAD_PRIORITY_TIME_CRITICAL settings can interfere with driver functions and can cause Windows to "hang" if kept in a prolonged state. To avoid these problems, a self-deleting app must exit cleanly upon a boolean return of TRUE. Developers need to make sure all ancillary processes and threads have finished and all handles are closed before calling the function. SelfDelete() should only be called at a program's main exit:

INT APIENTRY WinMain(...)
{
...

// on program exit
// close all handles etc.
if(!SelfDelete())
{
// add error messaging
}
return 0; // WinMain exit
}

It may be desirable to use a lower CPU allocation, such as:

SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_HIGHEST);

This allocation does not guarantee a complete cessation of the command shell process, but nevertheless works well.

Code Limitations
There is no error checking if the command shell cannot delete the file. Make sure the program file is not set with a "hidden," "system," or "read-only" attribute.
The explorer shell will always remove the program icon from view regardless of whether the command shell is able to actually delete the file. Pressing F5 will update the shell folder and correct any erroneous listings.
The command shell can only run a single command. Multiple commands such as to delete a file and remove its directory cannot be done without a script file.
Update
The code has been modified to work better on NT kernel computers with multiple processors. Windows allocates resources through a thread priority queue rather than by time-slicing CPU cycles. Two modifications have been made to the code:

The thread allocation to the program process has been increased prior to invoking the command shell process. This ensures the program process will always have priority in the resource queue. Threads created by the ShellExecuteEx function do not inherit the resource allocation of the calling process.
The NT kernel will transiently increase priority to whatever process is granted CPU resources. The SetProcessPriorityBoost function has been added to prevent this from happening to the command shell process.
////////////////////////////////////////////////////////

#include
#include

BOOL SelfDelete()
{
SHELLEXECUTEINFO sei;

TCHAR szModule [MAX_PATH],
szComspec[MAX_PATH],
szParams [MAX_PATH];

// get file path names:
if((GetModuleFileName(0,szModule,MAX_PATH)!=0) &&
(GetShortPathName(szModule,szModule,MAX_PATH)!=0) &&
(GetEnvironmentVariable("COMSPEC",szComspec,MAX_PATH)!=0))
{
// set command shell parameters
lstrcpy(szParams,"/c del ");
lstrcat(szParams, szModule);
lstrcat(szParams, " > nul");

// set struct members
sei.cbSize = sizeof(sei);
sei.hwnd = 0;
sei.lpVerb = "Open";
sei.lpFile = szComspec;
sei.lpParameters = szParams;
sei.lpDirectory = 0;
sei.nShow = SW_HIDE;
sei.fMask = SEE_MASK_NOCLOSEPROCESS;

// increase resource allocation to program
SetPriorityClass(GetCurrentProcess(),
REALTIME_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(),
THREAD_PRIORITY_TIME_CRITICAL);

// invoke command shell
if(ShellExecuteEx(&sei))
{
// suppress command shell process until program exits
SetPriorityClass(sei.hProcess,IDLE_PRIORITY_CLASS);
SetProcessPriorityBoost(sei.hProcess,TRUE);

// notify explorer shell of deletion
SHChangeNotify(SHCNE_DELETE,SHCNF_PATH,szModule,0);
return TRUE;
}
else // if error, normalize allocation
{
SetPriorityClass(GetCurrentProcess(),
NORMAL_PRIORITY_CLASS);
SetThreadPriority(GetCurrentThread(),
THREAD_PRIORITY_NORMAL);
}
}
return FALSE;
}

从Tony和DM的对话中,我们不难看到其设计思想是
1,avoid any Shell API calls
2,totally elliminates any "race" between processes. You might push the COMSPEC process to an even lower priority with this line:

SetThreadPriority(pi.hThread,THREAD_PRIORITY_IDLE);

Since the COMSPEC process is started suspended, you could increase resource allocation to main program AFTER the CreateProcess call, and that way you don't have to re-normalize allocatons on an error condition.

3,notify the Explorer shell of the deletion with:

SHChangeNotify(SHCNE_DELETE,SHCNF_PATH,szModule,0);

sometimes the Explorer doesn't update its directory listings in a timely enough manner.
rainstormmaster 2006-02-06
  • 打赏
  • 举报
回复
方法2:
下面的代码由Gary Nebbett写就.Gary Nebbett乃是WINDOWS NT/2000 NATIVE API REFERENCE的作者.乃NT系统一等一的高手.下面就分析一些他的这段代码.
这段代码在PROCESS没有结束前就将启动PROCESS的EXE文件删除了.
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;
}
现在,我们先看一下堆栈中的东西

偏移 内容
24 0
20 0
16 offset buf
12 address of ExitProcess
8 module
4 address of DeleteFile
0 address of UnmapViewOfFile

调用RET返回到了UnmapViewOfFile,也就是栈里的偏移0所指的地方.当进入UnmapViewOfFile的流程时,栈里见到的是返回地址DeleteFile和HMODUL module.也就是说调用完毕后返回到了DeleteFile的入口地址.当返回到DeleteFile时,看到了ExitProcess的地址,也就是返回地址.和参数EAX,而EAX则是buffer.buffer存的是EXE的文件名.由GetModuleFileName(module, buf, sizeof buf)返回得到.执行了DeleteFile后,就返回到了ExitProcess的函数入口.并且参数为0而返回地址也是0.0是个非法地址.如果返回到地址0则会出错.而调用ExitProcess则应该不会返回.
这段代码的精妙之处在于:
1.如果有文件的HANDLE打开,文件删除就会失败,所以,CloseHandle(HANDLE(4));是十分巧妙的一手.HANDLE4是OS的硬编码,对应于EXE的IMAGE.在缺省情况下,OS假定没有任何调用会关闭IMAGE SECTION的HANDLE,而现在,该HANDLE被关闭了.删除文件就解除了文件对应的一个句柄.
2.由于UnmapViewOfFile解除了另外一个对应IMAGE的HANDLE,而且解除了IMAGE在内存的映射.所以,后面的任何代码都不可以引用IMAGE映射地址内的任何代码.否则就OS会报错.而现在的代码在UnmapViewOfFile后则刚好没有引用到任何IMAGE内的代码.
3.在ExitProcess之前,EXE文件就被删除了.也就是说,进程尚在,而主线程所在的EXE文件已经没了.(WINNT/9X都保护这些被映射到内存的WIN32 IMAGE不被删除.)

Gary Nebbett果然是WIN系列平台的顶尖高手之一.能写出如此代码.独辟蹊径啊:)
据liron网友报告,本程序代码在XP下编译后运行,不能删除自己,奇怪的是我没有碰到,可能是系统权限问题。下面是补充一个纯VC实现

发信人: comealong (更深的蓝), 信区: VisualC
标 题: Re: 哪位对汇编熟悉的能不能帮忙改一下?
发信站: BBS 水木清华站 (Thu Aug 19 11:13:36 2004), 站内

// 给出这段代码的C++语言实现

#pragma check_stack (off)
static void DeleteSelf(HMODULE hModule , LPCTSTR lpszModueName)
{
typedef BOOL (WINAPI* PDeleteFile)(LPCTSTR);

#ifdef _UNICODE
PDeleteFile pDeleteFile = (PDeleteFile)GetProcAddress(
GetModuleHandle(_T("kernel32")) , _T("DeleteFileW") );
#else
PDeleteFile pDeleteFile = (PDeleteFile)GetProcAddress(
GetModuleHandle(_T("kernel32")) , _T("DeleteFileA") );
#endif // #ifdef _UNICODE

typedef VOID (WINAPI* PExitProcess)(UINT);
PExitProcess pExitProcess = (PExitProcess)GetProcAddress(
GetModuleHandle(_T("kernel32")) , _T("ExitProcess") );

CloseHandle(HANDLE(4));
UnmapViewOfFile(hModule);
pDeleteFile(lpszModueName);
pExitProcess(0);
}

static void AfterDeleteSelf(){}
#pragma check_stack ()

void main()
{
DWORD dwLen = ((BYTE *)(DWORD)AfterDeleteSelf -
(BYTE *)(DWORD)DeleteSelf);

TCHAR szModuleName[MAX_PATH];
HMODULE hModule = GetModuleHandle(NULL);
GetModuleFileName(hModule , szModuleName , MAX_PATH);

LPVOID lpBuf = _alloca(dwLen);

CopyMemory(lpBuf , DeleteSelf , dwLen);
void (*pf)(HMODULE , LPCTSTR) = (void (*)(HMODULE , LPCTSTR))lpBuf;

pf(hModule , szModuleName);
}

--
只有仰望是真实的,它使一颗卑微的灵魂有了飞跃的的光泽,
那是我在暗夜里怀念的道路有了更远的前方

※ 来源:·BBS 水木清华站 smth.org·[FROM: 221.137.246.*]

补充说明:

By 小林
From http://blog.csdn.net/i_like_cpp/archive/2004/11/27/195888.aspx

在Win9x下只要先对exe本身句柄执行FreeLibrary操作即可解除exe IMAGE在内存的映射,随后就可以通过调用DeleteFile来删除自身文件。
Win9x下的代码如下[selfkill-9x.c]:
#include "windows.h"
int main(int argc, char *argv[])
{
char buf[MAX_PATH];
HMODULE module;
module = GetModuleHandle(0);
GetModuleFileName(module, buf, MAX_PATH);
__asm
{
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push FreeLibrary
ret
}
return 0;
}

在WinNT/2K下则需要先调用CloseHandle关闭exe文件本身对应的IMAGE的句柄HANDLE[硬编码为4],然后调用UnmapViewOfFile解除了另外一个对应IMAGE的HANDLE,并且解除了程序本身在内存的映射对象,最后就可以用DeleteFile删除自身啦!(注意:本方法不适用于WinXP!)

WinNT/2K下的代码如下[selfkill-nt.c]:
#include "windows.h"
int main(int argc, char *argv[])
{
char buf[MAX_PATH];
HMODULE module;
module = GetModuleHandle(0);
GetModuleFileName(module, buf, MAX_PATH);
CloseHandle((HANDLE)4);
__asm
{
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
ret
}
return 0;
}


把上面用于Win9x及WinNT/2K下的代码综合起来,即把两种平台用到的API代码全部执行一遍,虽然在一种平台上可能会有几个API运行失败,有几个API会运行成功,但最后的结果exe程序文件在退出前就删除了自身!

Win9x和WinNT/2K下的代码如下[selfkill-9x+nt.c]:
#include "windows.h"
int main(int argc, char *argv[])
{
char buf[MAX_PATH];
HMODULE module;
module = GetModuleHandle(0);
GetModuleFileName(module, buf, MAX_PATH);
CloseHandle((HANDLE)4);

__asm
{
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push module
push UnmapViewOfFile
push FreeLibrary
ret
}
return 0;
}

  因为我自己在学习Win32下的汇编[MASM32],所以重新用汇编写了一遍,但结果却发现每次都执行失败,显示如图一的错误,

=========== 在此插入图一 ==============

通过反汇编比较发现原来由于MASM32编译器对API调用的编码和C编译器的不同,导致使用FreeLibrary或UnmapViewOfFile解除程序在内存的映射后,调用DeleteFile时又引用IMAGE映射地址内的代码[JMP DeleteFile],导致读内存执行错误。
错误分析
普通程序进行API调用时,编译器会将一个API调用语句编译为几个参数压栈指令后跟一条间接调用语句(这是指Microsoft编译器,Borland编译器使用JMP DWORD PTR [XXXXXXXXh])形式如下:

push arg1
push arg2
……
call dword ptr[XXXXXXXXh]
地址XXXXXXXXh在程序映像的导入(Import Section)段中,当程序被加载运行时,由装入器负责向里面添入API函数的地址;

一:用MASM32编译的程序其API函数调用格式为:
Call capi;
……
……
……
capi:
jmp dword ptr[XXXXXXXX];XXXXXXXX中存放着所调用的API函数真正地址

其中jmp dword ptr[XXXXXXXX]指令是由“编译器”在程序所有代码的后面自动加上的这样调用的好处是当多次调用同一API时可以减少代码体积,〈呵呵:)个人观点!〉

二:用C编译的程序其API函数调用格式为:
Call dword ptr [XXXXXXXX];XXXXXXXX地址中存放着所调用的API函数真正地址

正是由于上面API函数调用格式不同导致用MASM32编译的程序自删除失败,因为当调用UnmapViewOfFile后其中代码段的jmp dword ptr[XXXXXXXX]指令所处的代码节变成了不可读,后面的DeleteFile这个API的执行就会失败,程序出错!所以我们如果用MASM32编译这种自删除程序时,应该把push DeleteFile指令改为:

mov eax,DeleteFile
;取jmp dword ptr[XXXXXXXX]指令地址,机器码FF25XXXXXXXX
inc eax
inc eax
mov eax,dword ptr[eax]
push dword ptr[eax]
这样才是把DeleteFile的真正地址放入堆栈,当然用动态获取API也行,但不如这样代码少,下面是我改好的MASM32代码[selfkill9x-nt.asm]:

.386
.model flat, stdcall
option casemap :none

include windows.inc
include kernel32.inc
includelib kernel32.lib
.code
start:
mov ebp, esp
invoke GetModuleHandle,NULL ;获取自身模块句柄
mov ebx,eax
invoke GetModuleFileName,ebx,ebp,MAX_PATH ;获取自身路径
invoke CloseHandle,4 ;关闭exe文件本身对应的IMAGE的句柄[硬编码为4]
push 0;ExitProcess的参数
push 0
push ebp;DeleteFile的参数
mov eax,ExitProcess
inc eax
inc eax
mov eax,dword ptr[eax]
push dword ptr[eax];pushExitProcess

push ebx;UnmapViewOfFile的参数
mov eax,DeleteFile
inc eax
inc eax
mov eax,dword ptr[eax]
push dword ptr[eax];pushDeleteFile
push ebx;FreeLibrary的参数
mov eax,UnmapViewOfFile
inc eax
inc eax
mov eax,dword ptr[eax]
push dword ptr[eax];pushUnmapViewOfFile
push FreeLibrary;FreeLibrary不用改因为调用它时代码节还可以读
ret
endstart

rainstormmaster 2006-02-06
  • 打赏
  • 举报
回复
方法1:对于本程序在内存中的其它映像未做考虑,只是Demo而已

近日看到网友询问如何实现程序运行之后把自己删除的方法,不知大家对木马甚么的兴趣实在太浓,还是想要这样的效果:用户只要一运行程序,可执行文件就没有了,可是程序还是在跑,胆小的只怕要喊"鬼呀!","老婆,快出来看上帝"甚么的。其实最典型的用法是写反安装程序. 闲来无事,Bear掰到一种还算巧妙的“删除自己”的方法。
 
大家都知道,一般的程序运行的时候,可执行文件本身是被操作系统保护的,不能用改写的方式访问,更别提在本身还在运行的时侯删除自己了。在Lu0的主页上看到一种UNDOCUMENT的方法,通过改变系统底层的文件访问模式实现删除自己,那是实在功夫。我看 了很是佩服。但是有没有一种用在MSDN上就能查到的函数实现呢?有!Jeffrey Richter给我们做了一个范例:
 
DeleteMe.CPP
 
Module name: DeleteMe.cpp
Written by: Jeffrey Richter
Description: Allows an EXEcutable file to delete itself
**************************************************/
 
#include
#include
#include
 
/////////////////////////////////////////////////
 
int WINAPI WinMain(HINSTANCE h, HINSTANCE b, LPSTR psz, int n) {
 
// Is this the Original EXE or the clone EXE?
// If the command-line 1 argument, this is the Original EXE
// If the command-line >1 argument, this is the clone EXE
 
if (__argc == 1) {
 
// Original EXE: Spawn clone EXE to delete this EXE
// Copy this EXEcutable image into the user's temp directory
 
TCHAR szPathOrig[_MAX_PATH], szPathClone[_MAX_PATH];
GetModuleFileName(NULL, szPathOrig, _MAX_PATH);
GetTempPath(_MAX_PATH, szPathClone);
GetTempFileName(szPathClone, __TEXT("Del"), 0, szPathClone);
CopyFile(szPathOrig, szPathClone, FALSE);
 
//***注意了***:
// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL, OPEN_EXISTI
NG, FILE_FLAG_DELETE_ON_CLOSE, NULL);
 
// Spawn the clone EXE passing it our EXE's process handle
// and the full path name to the Original EXE file.
TCHAR szCmdLine[512];
HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE, GetCurrentProcessId());

wsprintf(szCmdLine, __TEXT("%s %d \"%s\""), szPathClone, hProcessOrig, szPat
hOrig);
STARTUPINFO si;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
CloseHandle(hProcessOrig);
CloseHandle(hfile);
 
// This original process can now terminate.
} else {
 
// Clone EXE: When original EXE terminates, delete it
HANDLE hProcessOrig = (HANDLE) _ttoi(__targv[1]);
WaitForSingleObject(hProcessOrig, INFINITE);
CloseHandle(hProcessOrig);
DeleteFile(__targv[2]);
// Insert code here to remove the subdirectory too (if desired).
 
// The system will delete the clone EXE automatically
// because it was opened with FILE_FLAG_DELETE_ON_CLOSE
}
return(0);
}
 
看懂了吗?
 
这一段程序思路很简单:不是不能在运行时直接删除本身吗?好,那么程序先复制(CLONE)一个自己,用复制品起动另一个进程,然后自己结束运行,则原来的EXE文件不被系统保护.这时由新进程作为杀手删除原来的EXE文件,并且继续完成程序其他的功能。

 
新进程在运行结束后,复制品被自动删除。这又是值得介绍的一个把戏了,注意:
// Open the clone EXE using FILE_FLAG_DELETE_ON_CLOSE
HANDLE hfile = CreateFile(szPathClone, 0, FILE_SHARE_READ, NULL,OPEN_EXISTIN
G, FILE_FLAG_DELETE_ON_CLOSE, NULL);
这里面的FILE_FLAG_DELETE_ON_CLOSE标志,这个标志是告诉操作系统,当和这个文件相关的所有句柄都被关闭之后(包括上面这个CREATEFILE创建的句炳),就把这个文件删除。几乎所有的临时文件在创建时,都指明了这个标志。另外要注意的是:在复制品进程对原始程序操刀之前,应该等待原进程退出.在这里用的是进程同步技术.用HANDLE hProcessOrig = OpenProcess(SYNCHRONIZE, TRUE,GetCurrentProcessId());得到原进程句柄.SYNCHRONICE标志在NT下有效,作用是使OpenProcess得到的句柄可以做为同步对象.复制品进程用WaitForSingleObject函数进行同步,然后一个DeleteFile,以及进行其它销毁证据(Jeffrey说:比如删目录)的工作,打完收工!
 
程序是基于CONSOLE的,通过传入的参数确定是原始的进程还是复制品新进程,并且得到需要操作的目标文件的信息(主要是路径),复制品放在系统的TEMP目录(GetTempPath得到),你也可以随便找个你认为安全的地方(比如:WINDOWS\SYSTEM32等等)。这里面没有甚么深的技术.再看其他的一些实现删除自己的例子,比如说在进程退出前,用fwrite等方法输出一个.BAT文件,在里面写几句DEL,然后WINEXEC一下这个BAT文件即可.玩儿过DOS的虫虫大多都会。今天又学一招,爽。
vo__ov 2006-02-06
  • 打赏
  • 举报
回复
谢谢,如果不用bat的怎么弄?
zyl910 2006-02-06
  • 打赏
  • 举报
回复
写个bat是最简单的办法

“要解除IMAGE在内存的映射什么的”在WinXP无效

请参考:
http://community.csdn.net/Expert/topic/3280/3280931.xml?temp=5.497378E-02

1,486

社区成员

发帖
与我相关
我的任务
社区描述
VB API
社区管理员
  • API
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧