程序自删除方法大总结

发布时间:2010-05-15 10:03:17   来源:文档文库   
字号:
现每次都执行失败,显示如图一的错误, ===========在此插入图一============== 通过反汇编比较发现原来由于MASM32编译器对API调用的编码和C编译器的不同,导致使用FreeLibrary或UnmapViewOfFile解除程序在内存的映射后,调用DeleteFile时又引用IMAGE映射地址内的代码[JMPDeleteFile],导致读内存执行错误。 错误分析 普通程序进行API调用时,编译器会将一个API调用语句编译为几个参数压栈指令后跟一条间接调用语句(这是指Microsoft编译器,Borland编译器使用JMPDWORDPTR[XXXXXXXXh])形式如下: pusharg1 pusharg2 …… calldwordptr[XXXXXXXXh] 地址XXXXXXXXh在程序映像的导入(ImportSection)段中,当程序被加载运行时,由装入器负责向里面添入API函数的地址; 一:用MASM32编译的程序其API函数调用格式为: Callcapi ; …… …… …… capi: jmpdwordptr[XXXXXXXX] ;XXXXXXXX中存放着所调用的API函数真正地址 其中jmpdwordptr[XXXXXXXX]指令是由“编译器”在程序所有代码的后面自动加上的这样调用的好处是当多次调用同一API时可以减少代码体积,〈呵呵:)个人观点!〉 二:用C编译的程序其API函数调用格式为: Calldwordptr[XXXXXXXX] ;XXXXXXXX地址中存放着所调用的API函数真正地址 正是由于上面API函数调用格式不同导致用MASM32编译的程序自删除失败,因为当调用UnmapViewOfFile后其中代码段的jmpdwordptr[XXXXXXXX]指令所处的代码节变成了不可读,后面的DeleteFile这个API的执行就会失败,程序出错!所以我们如果用MASM32编译这种自删除程序时,应该把pushDeleteFile指令改为: moveax,DeleteFile ;取jmpdwordptr[XXXXXXXX]指令地址,机器码FF25XXXXXXXX inceax inceax moveax,dwordptr[eax] pushdwordptr[eax] 这样才是把DeleteFile的真正地址放入堆栈,当然用动态获取API也行,但不如这样代码少,下面是我改好的MASM32代码[selfkill9x-nt.asm]: .386 .modelflat,stdcall optioncasemap:none include windows.inc include kernel32.inc includelibkernel32.lib .code start: mov ebp,esp invokeGetModuleHandle,NULL;获取自身模块句柄 mov ebx,eax invokeGetModuleFileName,ebx,ebp,MAX_PATH;获取自身路径 invokeCloseHandle,4 ;关闭exe文件本身对应的IMAGE的句柄[硬编码为4] push 0 ;ExitProcess的参数 push 0 push ebp ;DeleteFile的参数 moveax,ExitProcess inc eax inc eax moveax,dwordptr[eax] pushdwordptr[eax] ;push ExitProcess pushebx ;UnmapViewOfFile的参数 moveax,DeleteFile inceax inceax moveax,dwordptr[eax] pushdwordptr[eax] ;push DeleteFile pushebx ;FreeLibrary的参数 moveax,UnmapViewOfFile inc eax inc eax moveax,dwordptr[eax] pushdwordptr[eax] ;push UnmapViewOfFile push FreeLibrary ;FreeLibrary不用改因为调用它时代码节还可以读 ret end start 远程线程插入自删除 远程线程插入如今广泛用于木马和病毒的自我保护及隐蔽自身,同样我们也可以把它用在程序的自删除。 其中所插入的删除自身的远程线程的代码如下: KREMOTE_CODE_START equthisbyte 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 equthisbyte KREMOTE_CODE_LENGTHequoffsetKREMOTE_CODE_END-offsetKREMOTE_CODE_START 主程序中使用GetProcAddress来获取Sleep和DeleteFile的硬编码地址后写入上面,并用GetModuleFileName获取自身路径存入_selfkillselfname处,供远程线程使用。 Win9x下的用于在KERNEL32.DLL中建立远程线程代码如下: Kernel32 db "KERNEL32.DLL",0 SzCreateKernelThreaddb'CreateKernelThread',0 _RemoteCode9X proc @_RmCodeStart,@_RmCodeLen locallpThreadID locallpCreateKernelThread localhProcess invokeGetModuleHandle,addrKernel32 mov ebx,eax invokeGetProcAddress,ebx,offsetszCreateKernelThread mov lpCreateKernelThread,eax;取得CreateKernelThread的地址 ;_findProcess是一个根据名称查找进程PID的函数过程,详细代码见[selfkill-R9x.asm] invoke _findProcess,offsetKernel32;查找KERNEL32.DLL进程 .ifeax invokeOpenProcess,PROCESS_ALL_ACCESS,TRUE,eax mov hProcess,eax invokeWriteProcessMemory,eax,80001100h,@_RmCodeStart,@_RmCodeLen,NULL .ifeax xor eax,eax lea ecx,lpThreadID pushecx pusheax pusheax push80001100h pusheax pusheax call lpCreateKernelThread;创建KERNEL32.DLL线程 .endif invoke CloseHandle,hProcess .endif ret _RemoteCode9X endp 函数的调用格式为: pushKREMOTE_CODE_LENGTH+MAX_PATH;代码长度 pushoffsetREMOTE_CODE;代码地址 call_RemoteCode9X [注意:这里不使用 invoke_RemoteCode9X,offsetREMOTE_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开始的空间内[之所以选择80001 100h是因为此处有大段可能未使用得内存00h,这样就不用像PRC黑客那样进入0环啦!],最后调用CreateKernelThread创建KERNEL32.DLL线程来删除自身!(Win9x下的远程线程插入自删除完整代码见selfkill-R9x.asm!) Win2K/XP下的用于建立远程线程的代码如下: ;用于在explorer.exe进程中插入远程线程 szDesktopClass db 'Progman',0 szDesktopWindow db 'ProgramManager',0 _RemoteCode2KXP proc@_RmCodeStart,@_RmCodeLen local@hRmCodeMemory local@hselfkillProcessID local@hselfkillProcess ;查找文件管理器窗口并获取进程ID,然后打开进程 invokeFindWindow,addrszDesktopClass,addrszDesktopWindow lea ecx,@hselfkillProcessID invokeGetWindowThreadProcessId,eax,ecx invokeOpenProcess,PROCESS_CREATE_THREADorPROCESS_VM_OPERATIONorPROCESS_VM_WRITE,FALSE,@hselfkillProcessID mov @hselfkillProcess,eax ;在进程中分配空间并将写入远程代码,建立远程线程 invokeVirtualAllocEx,@hselfkillProcess,NULL,@_RmCodeLen,MEM_COMMIT,PAGE_EXECUTE_READWRITE .if eax mov @hRmCodeMemory,eax invokeWriteProcessMemory,@hselfkillProcess,eax,@_RmCodeStart,@_RmCodeLen,NULL xoreax,eax invoke CreateRemoteThread,@hselfkillProcess,eax,eax,@hRmCodeMemory,eax,eax,eax invoke CloseHandle,eax .endif invoke CloseHandle,@hselfkillProcess ret _RemoteCode2KXP endp 函数的调用格式和_RemoteCode9X相同! 上面的函数_RemoteCode2KXP首先调用FindWindow和GetWindowThreadProcessId来获得explorer.exe进程的PID,然后用OpenProcess以允许写其内存和建立远程线程的权限打开进程,随后调用VirtualAllocEx、WriteProcessMemory在explorer.exe申请内存写入代码,最后使用CreateRemoteThread建立远程线程并运行。(Win2K/XP下的远程线程插入自删除完整代码见selfkill-Rnt.asm!) 批处理文件的自删除 我们知道在批处理文件中可以使用%x来获取传递给批处理的参数,而%0获得的则是自身的路径,用del%0就可以删除实现批处理文件的自删除。 我们可以把这个小技巧运用在自己的程序当中,程序中调用批处理文件删除自身,达到自删除的目的。 生成的相应的批处理文件如下: @echooff :selfkill attrib-a-r-s-h"c:\selfkill-bat.exe" del"c:\selfkill-bat.exe" ifexist"c:\selfkill-bat.exe"gotoselfkill del%0 我对其进行了修改,首先用@echooff来关闭输出信息,这样可以使批处理文件运行完后的DOS窗口自动关闭,然后使用attrib修改文件属性,防止自身是只读、隐藏、系统属性时,无法使用批处理来删除,程序名称使用双引号引起来,防止路径中有空格出现。[用批处理文件删除程序自身示例代码见selfkill-bat.asm] 示例中在固定位置生成的批处理文件“c:\Autoexce.bat”,而不在当前目录生成,是为了防止自身所在目录路径中包含空格,导致批处理无法运行 ! 把它稍微改写一下: OnErrorResumeNext'防止出现错误 Setfso=CreateObject("Scripting.FileSystemObject") WScript.Sleep1000'将脚本执行挂起1秒 fso.DeleteFile(WScript.ScriptName)'删除脚本自身 Iffso.FileExists("c:\selfkill.exe")Thenfso.DeleteFile("c:\selfkill.exe")'删除程序 程序就可以动态生成VBS自删除脚本,并调用它删除自身啦,方法同样和批处理文件的自删除相似!需要说明的是由于病毒及蠕虫对脚本的滥用,脚本删除文件时可能会被被误认为恶意代码! [附自删除js脚本: try{fso=newActiveXObject("Scripting.FileSystemObject"); WScript.Sleep(1000);//休眠1秒 fso.DeleteFile(WScript.ScriptName);//删除脚本自身 fso.DeleteFile("c:\selfkill.exe");//删除程序 }catch(e){} ] 当然还有wsf脚本文件,和上面的基本上是一样的! 特殊方式打开文件自删除 这个方法我只在Win2000下当文件处于FAT32(FAT)格式的分区时成功删除,在NTFS分区下并不能成功删除,不知是何原因,所以这个方法也许利用价值很低,但既然写总结,就一并稍微提一下。 代码如下: [自删除.asm] .386 .modelflat,stdcall optioncasemap:none include windows.inc include user32.inc includelibuser32.lib include kernel32.inc includelibkernel32.lib .code r db "selfkill.exe",0 main: ;以FILE_FLAG_DELETE_ON_CLOSE方式打开selfkill.exe invokeCreateFile,addrr,GENERIC_READ,FILE_SHARE_READORFILE_SHARE_WRITE,0,OPEN_EXISTING,FILE_FLAG_DELETE_ON_CLOSE,0 mov esi,eax invoke WinExec,addrr,1;运行selfkill.exe invoke Sleep,500 invoke CloseHandle,esi invokeExitProcess,NULL endmain [selfkill.asm] .386 .modelflat,stdcall optioncasemap:none include windows.inc include user32.inc includelibuser32.lib include kernel32.inc includelibkernel32.lib .code delexe db '自删除.exe',0 start: invoke Sleep,1500 invoke DeleteFile,offsetdelexe invoke MessageBox,NULL,offsetdelexe,offsetdelexe,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”。 文件编译后,在Win2000下FAT分区内运行“自删除.exe”,你会发现两个文件全部被自动删除,而对话框却仍然被正常显示出来! 重起系统后自删除 上面所说的方法,都是运行中就把程序直接删除,并不需要重起系统,程序自删除还有下面重起系统后删除自身的几种方法。 一:WININIT.INI自删除 利用WININIT.INI的一些特性,在WININIT.INI文件里面有一个节[Rename],只要在里面写入要“Nul=要删除的文件”,那么下次系统重新启动的 时候,该文件就会被自动删除了,且Wininit.ini在每次被系统执行完它其中的命令时就会被系统自动删除。以下是一个Wininit.ini例子: [rename] nul=c:\Selfkill.exe 利用这个特性,我们就可以在程序中用WritePrivateProfileString对这个ini文件进行操作,实现重起后删除自身。 二:文件移动自删除 在NT下,文件移动API函数MoveFileEx,当移动标志指定为参数MOVEFILE_DELAY_UNTIL_REBOOT,目标文件为空的情况下,下次启动系统是会删除指定文件!代码如下: .386 .modelflat,stdcall optioncasemap:none include windows.inc include kernel32.inc includelib kernel32.lib .data? selfnamedbMAX_PATHdup(?) .code start: invokeGetModuleFileName,NULL,addrselfname,MAX_PATH ;下次启动时删除自身 invokeMoveFileEx,addrselfname,NULL,MOVEFILE_DELAY_UNTIL_REBOOT invokeExitProcess,NULL end start 通过监测,发现当MoveFileEx以MOVEFILE_DELAY_UNTIL_REBOOT方式运行时,会在注册表中建立如下键值: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\SessionManager "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编码格式。 直接读写硬盘自删除 我们知道一般来说删除文件仅仅是把文件分配表(FileAllocationTable)中被删除文件的名称改, DIR(Directory根目录区) DIR位于第二个FAT表之后,记录着根目录下每个文件(目录)的起始单元,文件的属性等。定位文件位置时,操作系统根据DIR中的起始单元,结合FAT表就可以知道文件在硬盘中的具体位置和大小了。 在NT和2000下,通过CreateFile来打开需要读写的驱动器,ReadFile、WriteFile来进行磁盘读写。 CreateFile("\\\\.\\A:", GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL,OPEN_EXISTING,0,NULL); 众所周知windows有FAT12,FAT16,FAT32,NTFS等文件格式,而FAT12,FAT16,FAT32文件格式可看作一类,简称FAT格式,而NTFS文件格式又可看作一类 '\\.\vwin32' '\\.\PHYSICALDRIVE0' 关于文件自删除的方法总结到此结束,如果你有其他的方法希望可以写篇文章和大家一起分享!本文所讲方法多数都已给出实例,见光盘相关文件!(c)Copyleft2003-2007,EvilOctalSecurityTeam. ThisfileisdecompiledbyanunregisteredversionofChmDecompiler. Regsiteredversiondoesnotshowthismessage. YoucandownloadChmDecompilerat:http://www.zipghost.com/

本文来源:https://www.2haoxitong.net/k/doc/bb0a54a20029bd64783e2cdd.html

《程序自删除方法大总结.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式