程序自刪除方法大總結

程序自刪除方法大總結 icyfoxlovelace/冰狐浪子
       
       程序的自刪除早已經不是什麼新鮮的話題了,對於各位大蝦來說是更是比較容易的事情,但想想自己剛學時遇到的種種錯誤,我覺得有必要把自己所知道的各種 方法總結一下,希望對新手的學習能夠有所幫助。程序的自刪除廣泛用於反安裝程序最後的自刪除(環保呀!),當然更多見於木馬、病毒首次安裝的自動銷燬 ^*^,至於用於何種用途就看你自己啦!經典自刪除說到程序的自刪除就不能不說由 Gary Nebbett 等大蝦所寫的代碼,經典之作呀!代碼採用C語言內嵌彙編asm: 在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 

       遠程線程插入自刪除遠程線程插入如今廣泛用於木馬和病毒的自我保護及隱蔽自身,同樣我們也可以把它用在程序的自刪除。 其中所插入的刪除自身的遠程線程的代碼如下:
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!)批 處理文件的自刪除我們知道在批處理文件中可以使用 %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修改文件屬性,防止自身是隻讀、隱藏、系統屬性時,無法 使用批處理來刪除,程序名稱使用雙引號引起來,防止路徑中有空格出現。[用批處理文件刪除程序自身示例代碼見selfkill-bat.asm] 示例中在固定位置生成的批處理文件“c:/Autoexce.bat”,而不在當前目錄生成,是爲了防止自身所在目錄路徑中包含空格,導致批處理無法運 行,生成批處理後使用WinExec隱蔽運行,不顯示DOS 窗口。 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]文件,和批處理的利用 方式一樣以隱蔽運行方式調用!腳本自刪除歡樂時光的泛濫,想必很多人對於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分區下並不能成功刪除,不知是何原因,所以這個方法也許利用價值很低,但既然寫總結,就一併稍微提一下。代碼如下: [自刪除.asm] .386 .model flat, stdcall option casemap:none include windows.inc include user32.inc includelib user32.lib include kernel32.inc includelib kernel32.lib .code rdb"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 movesi,eax invokeWinExec,addr r,1 ;運行selfkill.exe invokeSleep,500 invokeCloseHandle,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 delexedb'自刪除.exe',0 start: invokeSleep,1500 invokeDeleteFile,offset delexe invokeMessageBox,NULL,offset delexe,offset delexe,MB_OK invokeExitProcess,NULL endstart 首先在“自刪除.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 .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 endstart 通過監測,發現當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編碼格式。直接讀寫硬盤自刪除我們知道一般來說刪除文件僅僅是把文件分配表(File Allocation Table)中被刪除文件的名稱改, 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' 關於文件自刪除的方法總結到此結束,如果你有其他的方法希望可以寫篇文章和大家一起分享!本文所講方法多數都已給出實例,UploadFile= tmp_D4B4B4FAC2EB_1095750519.rar]

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=539650

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章