频道栏目
首页 > 资讯 > win7激活工具 > 正文

程序自删除方法大总结

04-11-07        来源:[db:作者]  
收藏   我要投稿
文章作者:icyfoxlovelace/冰狐浪子[EST]
信息来源:本文章首发于《黑客防线》

程序的自删除早已经不是什么新鲜的话题了,对于各位大虾来说是更是比较容易的事情,但想想自己刚学时遇到的种种错误,我觉得有必要把自己所知道的各种方法总结一下,希望对新手的学习能够有所帮助。
程序的自删除广泛用于反安装程序最后的自删除(环保呀!),当然更多见于木马、病毒首次安装的自动销毁^*^,至于用于何种用途就看你自己啦!
经典自删除
说到程序的自删除就不能不说由 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]         ;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和DeleteF
相关TAG标签
上一篇:黑客防线---主机外部的危险
下一篇:黑客是共享 黑客是沉寂
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站