会员登陆  支付方式  联系我们  在线客服  网站地图       
首页 关于域浪 互联网数据中心业务、主机托管、主机租用、机架租用、带宽租用、机房介绍、机房对比、CCN网络加速 adsl专线、深圳adsl专线 虚拟主机、域名注册、数据库、企业邮局、动态域名 网络安全、网络临近平台、安全服务、防火去墙租用、安全产品、域浪抗DDOS防火墙、NetScreen防火墙 技术支持  
   当前位置:首页 >> 技术支持 >> 网络安全 >> 程序自删除七大方法总结
 
精华文章
    端口大全  
    OSI七层模型介绍  
    用注册表为操作系统砌...  
    堵住域名和邮件的漏洞  
    防火墙技术专题  
    防火墙技术专题续  
    深入浅出谈防火墙  
    网络安全  
    关闭端口详解--防黑必...  
    交换机的命令  
    网络常见攻击与防范完...  
    BBS漏洞  
    任务管理器进程全解  
    提升ADSL速度的五大招...  
    网页脚本攻击防范全攻...  
    程序自删除七大方法总...  
    网络基础教程全文  
    防火墙程序在使用中的...  
    3389远程控制实用技巧  
    防范网络炸弹(五)  
    防范网络炸弹(四)  
    防范网络炸弹(三)  
    防范网络炸弹(二)  
    防范网络炸弹(一)  
    修复被锁定的注册表  
    8种Windows安全模式解...  
    Win2000下修改注册表加...  
    巧妙设置路由保护内网...  
  更多>>  
   网络安全
 程序自删除七大方法总结
    程序的自删除早已经不是什么新鲜的话题了,对于各位大虾来说是更是比较容易的事情,但想想自己刚学时遇到的种种错误,我觉得有必要把自己所知道的各种方法总结一下,希望对新手的学习能够有所帮助。程序的自删除广泛用于反安装程序最后的自删除(环保),当然更多见于木马、病毒首次安装的自动销毁,至于用于何种用途就看你自己了!



经典自删除

    说到程序的自删除就不能不说由Gary Nebbett等大虾所写的代码,经典之作!代码采用C语言内嵌汇编asm。在Windows9x下只要先对EXE本身句柄执行FreeLibrary操作即可解除EXE IMAGE在内存的映射,随后就可以通过调用DeleteFile来删除自身文件。Windows 9x下的代码如下[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;

}



    在Windows NT/2K下则需要先调用CloseHandle关闭EXE文件本身对应的IMAGE的句柄HANDLE[硬编码为4],然后调用UnmapViewOfFile解除了另外一个对应IMAGE的HANDLE,并且解除了程序本身在内存的映射对象,最后就可以用DeleteFile删除自身了(注意:本方法不适用于Windows XP)。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;



    把上面用于Windows 9x及WinNT/2K下的代码综合起来,即把两种平台用到的API代码全部执行一遍,虽然在一种平台上可能会有几个API运行失败,有几个API会运行成功,但最后的结果EXE程序文件在退出前就删除了自身。Windows 9x和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],所以重新用汇编写了一遍,但结果却发现每次都执行失败,显示如图1所示的错误,



    通过反汇编比较发现原来由于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] ;push ExitProcess



push ebx ;UnmapViewOfFile的参数

mov eax,DeleteFile

inc eax

inc eax

mov eax,dword ptr[eax]

push dword ptr[eax] ;push DeleteFile

push ebx ;FreeLibrary的参数

mov eax,UnmapViewOfFile

inc eax

inc eax

mov eax,dword ptr[eax]

push dword ptr[eax] ;push UnmapViewOfFile

push FreeLibrary ;FreeLibrary不用改因为调用它时代码节还可以读

ret

end start



远程线程插入自删除

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

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处,供远程线程使用。Windows 9x下的用于在KERNEL32.DLL中建立远程线程代码如下:

Kernel32 db "KERNEL32.DLL",0

SzCreateKernelThread db 'CreateKernelThread',0

_RemoteCode9X proc @_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

invoke CloseHandle,hProcess

.endif

ret

_RemoteCode9X endp

函数的调用格式为:

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线程来删除自身! 



Win2K/XP下的用于建立远程线程的代码如下:

;用于在explorer.exe进程中插入远程线程

szDesktopClass db 'Progman',0

szDesktopWindow db 'Program Manager',0

_RemoteCode2KXP proc @_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

.if eax

mov @hRmCodeMemory,eax

invoke WriteProcessMemory,@hselfkillProcess,eax,@_RmCodeStart,@_RmCodeLen,NULL

xor eax,eax

invoke CreateRemoteThread,@hselfkillProcess,eax,eax,@hRmCodeMemory,eax,eax,eax

invoke CloseHandle,eax

.endif

invoke CloseHandle,@hselfkillProcess

ret

_RemoteCode2KXP endp

    上面的函数_RemoteCode2KXP首先调用FindWindow和GetWindowThreadProcessId来获得explorer.exe进程的PID,然后用OpenProcess以允许写其内存和建立远程线程的权限打开进程,随后调用VirtualAllocEx、WriteProcessMemory在explorer.exe申请内存写入代码,最后使用CreateRemoteThread建立远程线程并运行。



批处理文件的自删除

    我们知道在批处理文件中可以使用%x来获取传递给批处理的参数,而%0获得的则是自身的路径,用“del %0”就可以删除实现批处理文件的自删除。

    我们可以把这个小技巧运用在自己的程序当中,程序中调用批处理文件删除自身,达到自删除的目的。生成的相应的批处理文件如下:

@echo off

:selfkill

attrib -a -r -s -h "c:\selfkill-bat.exe"

del "c:\selfkill-bat.exe"

if exist "c:\selfkill-bat.exe" goto selfkill

del %0

    我对其进行了修改,首先用@echo off来关闭输出信息,这样可以使批处理文件运行完后的DOS窗口自动关闭,然后使用Attrib修改文件属性,防止自身是只读、隐藏、系统属性时,无法使用批处理来删除,程序名称使用双引号引起来,防止路径中有空格出现。

    示例中在固定位置生成的批处理文件“c:\Autoexce.bat”,而不在当前目录生成,是为了防止自身所在目录路径中包含空格,导致批处理无法运行,生成批处理后使用WinExec隐蔽运行,不显示DOS 窗口。



DOS虚拟机下的自删除

这个方法乃好友“抑郁天使”所提供,感谢!代码如下:

#include <stdio.h>

int main(int argc,char *argv[])

{

unlink(argv[0]);

return 0;

}

    unlink相信学 C语言的朋友比较熟悉吧,就是删除指定文件,使用TC2.0把上面代码编译为DOS下16位的程序,执行看看,是不是在闪出一个DOS窗口后,程序不见了?!我们再把上面的程序改写一下,使其可以接受参数:

#include <stdio.h>

int main(int argc,char *argv[])

{

sleep(1); //休眠1秒

if(argc==2)

unlink(argv[1]); //删除程序(参数一)

unlink(argv[0]); //删除自身

return 0;

}

    通过对其反汇编分析,结合测试,这个自删除的原因应该为DOS下的程序在Windows下是通过虚拟机执行(Windows 2000下为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文件,和批处理的利用方式一样以隐蔽运行方式调用!



脚本自删除

    欢乐时光的泛滥,想必很多人对于VBS脚本有所了解了,由于脚本是解释执行的,所以在运行时可以被删除,也就是说脚本文件删除自身后不影响后面的代码执行。我们来做个实验,把下面的脚本保存为selfkill.vbs或selfkill.vbe:

Set fso = CreateObject("Scripting.FileSystemObject")

f = fso.DeleteFile(WScript.ScriptName)

WScript.Echo( WScript.ScriptName)

    然后运行它,是不是发现selfkill.vbs神奇的消失了?而后面的对话框却被正常显示出来。上面的脚本调用FSO控件,使用WSH中Wscript对象得ScriptName属性,得到脚本自身的文件名,并调用FSO的DeleteFile方法删除自身。把它稍微改写一下:

On Error Resume Next '防止出现错误

Set fso = CreateObject("Scripting.FileSystemObject")

WScript.Sleep 1000 '将脚本执行挂起1秒

fso.DeleteFile(WScript.ScriptName) '删除脚本自身

If fso.FileExists("c:\selfkill.exe") Then fso.DeleteFile("c:\selfkill.exe") '删除程序

    程序就可以动态生成VBS自删除脚本,并调用它删除自身了,方法同样和批处理文件的自删除相似!需要说明的是由于病毒及蠕虫对脚本的滥用,脚本删除文件时可能会被被误认为恶意代码!

自删除js脚本:

try{fso = new ActiveXObject("Scripting.FileSystemObject");

WScript.Sleep(1000);//休眠1秒

fso.DeleteFile(WScript.ScriptName);//删除脚本自身

fso.DeleteFile("c:\selfkill.exe");//删除程序

}catch(e){}

当然还有WSF脚本文件,和上面的基本上是一样的。



特殊方式打开文件自删除

    这个方法我只在Win2000下当文件处于FAT32(FAT)格式的分区时成功删除,在NTFS分区下并不能成功删除,不知是何原因,所以这个方法也许利用价值很低,但既然写总结,就一并稍微提一下。代码如下:

.386

.model flat, stdcall

option casemap:none

include windows.inc

include user32.inc

includelib user32.lib

include kernel32.inc

includelib kernel32.lib

.code

r db "selfkill.exe",0

main:

;以FILE_FLAG_DELETE_ON_CLOSE方式打开selfkill.exe

invoke CreateFile,addr r,GENERIC_READ,FILE_SHARE_READ OR FILE_SHARE_WRITE , 0 , OPEN_EXISTING , FILE_FLAG_DELETE_ON_CLOSE,0

mov esi,eax

invoke WinExec,addr r,1 ;运行selfkill.exe

invoke Sleep,500

invoke CloseHandle,esi

invoke ExitProcess, NULL

end main



[selfkill.asm]

.386

.model flat,stdcall

option casemap:none

include windows.inc

include user32.inc

includelib user32.lib

include kernel32.inc

includelib kernel32.lib

.code

delexe db '自删除.exe',0

start:

invoke Sleep,1500

invoke DeleteFile,offset delexe

invoke MessageBox,NULL,offset delexe,offset delexe,MB_OK

invoke ExitProcess,NULL

end start



    首先在“自删除.asm”中使用CreateFile以FILE_FLAG_DELETE_ON_CLOSE(文件被关闭后立即被系统自动删除)方式打开selfkill.exe文件,然后运行selfkill.exe,休眠0.5秒后关闭文件(也就是删除selfkill.exe),在“selfkill.asm”中首先休眠1.5秒,然后删除“自删除.exe”。

文件编译后,在Windows 2000下FAT分区内运行“自删除.exe”,你会发现两个文件全部被自动删除,而对话框却仍然被正常显示出来!



重起系统后自删除

    上面所说的方法,都是运行中就把程序直接删除,并不需要重起系统,程序自删除还有下面重起系统后删除自身的两种方法。

1.WININIT.INI自删除

    利用WININIT.INI的一些特性,在WININIT.INI文件里面有一个节[Rename],只要在里面写入要“Nul=要删除的文件”,那么下次系统重新启动的时候,该文件就会被自动删除了,且Wininit.ini在每次被系统执行完它其中的命令时就会被系统自动删除。以下是一个Wininit.ini例子:

[rename] 

nul=c:\Selfkill.exe

利用这个特性,我们就可以在程序中用WritePrivateProfileString 对这个ini文件进行操作,实现重起后删除自身。

2.文件移动自删除

    在NT下,文件移动API 函数MoveFileEx,当移动标志指定为参数MOVEFILE_DELAY_UNTIL_REBOOT,目标文件为空的情况下,下次启动系统是会删除指定文件!代码如下:

.386

.model flat, stdcall

option casemap :none

include windows.inc

include kernel32.inc

includelib kernel32.lib

.data?

selfname db MAX_PATH dup(?)

.code

start:

invoke GetModuleFileName,NULL,addr selfname,MAX_PATH

;下次启动时删除自身

invoke MoveFileEx,addr selfname,NULL,MOVEFILE_DELAY_UNTIL_REBOOT

invoke ExitProcess,NULL

end start

通过监测,发现当MoveFileEx以MOVEFILE_DELAY_UNTIL_REBOOT方式运行时,会在注册表中建立如下键值:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager

"PendingFileRenameOperations"=hex(7):5c,00,3f,00,3f,00,5c,00,43,00,3a,00,5c,00,\

73,00,65,00,6c,00,66,00,6b,00,69,00,6c,00,6c,00,2e,00,65,00,78,00,65,00,00,\

00,00,00,00,00

    PendingFileRenameOperations键值类型为REG_MULTI_SZ,在注册表编辑器中值显示为:\??\c:\selfkill.exe,是Unicode编码格式。
  • 上一篇文章: 网页脚本攻击防范全攻略
  • 下一篇文章: 网络基础教程全文
  • 域浪网络ISP经营许可证 深圳地址:深圳市罗湖区宝安北路国际商品交易大厦七楼C30室
    Tel:0755-82266883/82267566 Fax:0755-82261966
    邮编:518000 
                        Copyright © 2006-2008 elang.cn All Rights Reserved 深圳市域浪网络技术有限公司版权所有