首页
社区
课程
招聘
关于自删除程序,我有的地方看不懂
发表于: 2004-11-11 20:04 7794

关于自删除程序,我有的地方看不懂

2004-11-11 20:04
7794
下面的语句摘录自《精华4》,但有的语句我看不太懂,谁能解释一下吗?
下面的代码由Gary Nebbett写就.Gary Nebbett乃是WINDOWS NT/2000 NATIVE API REFERENCE的作者.乃NT系统一等一的高手.下面就分析一些他的这段代码.
这段代码在PROCESS没有结束前就将启动PROCESS的EXE文件删除了.
int main(int argc, char *argv[])    //这里为什么用argc和argv[]?初始数值可以随便吗?
{
    HMODULE module = GetModuleHandle(0);
    CHAR buf[MAX_PATH];
    GetModuleFileName(module, buf, sizeof buf);
    CloseHandle(HANDLE(4));  //这里的HANDLE(4)是属于系统默认的吗?有什么意义?
    __asm {
        lea    eax, buf
        push    0
        push    0
        push    eax
        push    ExitProcess
        push    module
        push    DeleteFile
        push    UnmapViewOfFile    //这里压栈完了却为什么没启用API函数?只是为了让压栈的内容为返回的数值吗?
        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不被删除。

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 1
支持
分享
最新回复 (15)
雪    币: 4908
活跃值: (2343)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
2
1、如果是用WIN32汇编以上的代码,第一行的int main(int argc, char *argv[])    还有没有意义?是不是相当于一个 start:  ?

2、上面代码最后的分析,UnmapViewOfFile解除了另外一个对应IMAGE的HANDLE,而且解除了IMAGE在内存的映射.
   这里为什么用“另外一个”这个词?不是解除的程序,是解除程序本身的代码,又会是什么?
3、在ExitProcess之前,EXE文件就被删除了,从这里来看,在压栈的Exitprocess之后,可以任意增加自己的代码吗?就是可以执行程序中的任何功能?

4、遗憾的是本人对C并不熟悉,所以无法编译调试。如果那位大哥可以编译出程序的话,请附到附件中,谢谢。
2004-11-11 20:17
0
雪    币: 203
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这个程序在VC 中是直接可以编译的。
至于main 函数,这是c 的Runtime libary 所提供的一个对外部开发者所提供的函数,这样所有的开发者写程序的时候,就可以从main 开始了。 其实main 不是必要的,不过对于 c 的runtime libary ,是调用了main 的这个函数,函数的入口参数也是 Runtime libary 传递的,参数的意义
main(int argc,char *argv[],char *env[])
第一个参数就是,函数命令行参数的格式,
第二个参数就是,命令行参数的字符串集合了
第三个参数就是,程序运行的环境,里面是一些环境变量。
这个冬冬和汇编就有一点不同了。汇编是可以不借助Runtime library 就可以玩的冬冬。除了那个CloseHandle 的硬编码外,是固定的,需要操作系统的知识,其他的东西,老兄要是对于汇编比较熟悉的话,对你应该也不难。 :0
2004-11-11 21:46
0
雪    币: 494
活跃值: (629)
能力值: ( LV9,RANK:1210 )
在线值:
发帖
回帖
粉丝
4
最初由 oep1 发布
1、如果是用WIN32汇编以上的代码,第一行的int main(int argc, char *argv[]) 还有没有意义?是不是相当于一个 start: ?

2、上面代码最后的分析,UnmapViewOfFile解除了另外一个对应IMAGE的HANDLE,而且解除了IMAGE在内存的映射.
这里为什么用“另外一个”这个词?不是解除的程序,是解除程序本身的代码,又会是什么?
3、在ExitProcess之前,EXE文件就被删除了,从这里来看,在压栈的Exitprocess之后,可以任意增加自己的代码吗?就是可以执行程序中的任何功能?
........


这段代码的奥秘在于其退出的
方式。从ret开始,再也没有用户
的代码被执行了。
2004-11-11 22:32
0
雪    币: 4908
活跃值: (2343)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
最初由 softworm 发布



这段代码的奥秘在于其退出的
方式。从ret开始,再也没有用户
........


谢谢上面各位热心的朋友。

开始的时候我还以为是有什么古怪呢。
我明白了:就是可以让自己写的程序执行任何的代码,但最后准备退出时候引用最后那段汇编代码,就可以把程序自己删除了,执行完最后的那个RET后,程序从内存中消失,而程序本身也消失了,对吧。:)

我编译了如下,虽然不能删除本身,但调试最后是无法跟踪的,因为把自己的代码全部删除了;不能删除的原因可能是那个HANDLE(4)我没太弄明白。谁可以告诉我在这里如何表示那个HANDLE(4)
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\kernel32.lib
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

.data
MsgBoxCaption  db "Iczelion Tutorial No.1",0
MsgBoxText       db "Win32 Assembly is Great!",0
progname db 256 dup(0)

.data?
module HMODULE ?

.code
start:
invoke GetModuleHandle,0
mov module,eax
invoke GetModuleFileName,module,addr progname,256
invoke MessageBox, NULL, addr MsgBoxText, addr MsgBoxCaption, MB_OK

invoke CloseHandle,HANDLE+4   ;;;这里如何表示???
lea eax,progname
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
ret
invoke ExitProcess,NULL
end start
2004-11-11 23:44
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
6
int main(int argc, char *argv[])  是标准ANSI C 的参数格式,所有用 C 语言写的程序都可以这样写,跟个别 OS 无关。在一般不需要接收参数的时候,人们写 int main( ) ,两种都是合法。
Argc : 参数的数量
Argv[] : 存放参数的数组

OS 有责任把参数设定正确,交到执行的程序

这是 Win32 console 程序的写法,写 win32 GUI 程序我们会使用  int WINAPI WinMain(
  HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow );

2004-11-12 08:11
0
雪    币: 4908
活跃值: (2343)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
7
最初由 riijj 发布
int main(int argc, char *argv[]) 是标准ANSI C 的参数格式,所有用 C 语言写的程序都可以这样写,跟个别 OS 无关。在一般不需要接收参数的时候,人们写 int main( ) ,两种都是合法。
Argc : 参数的数量
Argv[] : 存放参数的数组

OS 有责任把参数设定正确,交到执行的程序
........

谢谢了。
我还是不懂我上面写的那段代码为什么运行后不能删除它自己?上面的代码就是显示一个MESSAGEBOX后,应该会删除它自己,但运行到UNMAPVIEW后,就无法跟踪了,所以看不到效果,运行结束后程序也没删除它自己。
2004-11-12 11:14
0
雪    币: 4908
活跃值: (2343)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
8
下面是WIN32论坛里的相关的文章http://board.win32asmcommunity.net/viewtopic.php?t=4190
2004-11-12 12:09
0
雪    币: 494
活跃值: (629)
能力值: ( LV9,RANK:1210 )
在线值:
发帖
回帖
粉丝
9
我也不懂为什么直接使用4作为
CloseHandle的参数。

瞧瞧这个,很精彩的文章。

http://www.catch22.net/tuts/selfdel.asp

你的代码中应该直接用4作为CloseHandle的参数。
这个程序在XP下删不掉自己。
2004-11-12 13:10
0
雪    币: 2319
活跃值: (565)
能力值: (RANK:300 )
在线值:
发帖
回帖
粉丝
10
如果程序需要自我删除,有一个比较简单的方法

程序可以把自己复制,再以 CreateFile 打开,参数是 FILE_FLAG_DELETE_ ON_CLOSE

原程序把子程序运行,输入两个参数,第一个是原程序自己的 handle,第二个是原程序的路径。这时候原程序可以终止

新生的子程序检查输入的参数,知道自己的身份是子程序,检查参数后,子程序依照路径位置把原程序的 exe 删除。子程序完成工作后便终止,这时候 windows 会把子程序也删掉,因为子程序被 FILE_FLAG_DELETE_ ON_CLOSE 打开

英文原文
http://www.systemp.net/forum/viewtopic.php?t=24
2004-11-12 14:39
0
雪    币: 4908
活跃值: (2343)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
11
TO softworm:是,我的系统是XP,编译后就删除不掉本身,所以我就奇怪 ,后来我把WIN32ASM论坛上的人发布的程序也挡下来,用程序自身的CODE,确实不能删除自己。另:我上面写的那段程序,在98下运行后, 也是删除不掉自身的,开始我以为最后那段ASM代码中的压栈顺序有关系,后来变换了压栈顺序,也是一样不行的。

TO riijj:附件中是WIN32ASM论坛上的一个人用WIN32汇编产生一个BAT的方法写的程序,在程序执行的时候,在系统TEMP目录产生一个BAT文件循环来删除程序自身,循环到程序退出后被正确删除为止。这个方法在XP和98下都可以删除自己(WIN2K下没测试)。

附件中是WIN32ASM论坛上原代码(用.BAT的方法删除自己),为WIN32汇编写成。
附件:delself.rar
2004-11-12 18:55
0
雪    币: 494
活跃值: (629)
能力值: ( LV9,RANK:1210 )
在线值:
发帖
回帖
粉丝
12
W2K下可以,那段代码我也试过的;)
2004-11-12 19:13
0
雪    币: 253
活跃值: (250)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
13
lea eax,progname
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
ret

这段代码的妙处是使内存中的代码消失后,还能自动顺序执行UnmapViewOfFile、DeleteFile、ExitProcess三个函数,实现删除自身的目的。
2004-11-12 19:53
0
雪    币: 4908
活跃值: (2343)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
14
最初由 moon 发布
lea eax,progname
push 0
push 0
push eax
push ExitProcess
........


是,上面的那些连接文章里,就可以看出来了。

区别是XP和NET和2003下不能使用

NT/2000下用上面的方法可以顺序执行;98/95下用FreeLibrary代替上面的UnmapViewOfFile

因为影像删除后就不能用调试工具调试了,所以不知道为什么在XP下不能删除程序自己。
2004-11-12 20:21
0
雪    币: 390
活跃值: (707)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
15
UnMapView以后,进程的虚拟空间没了,现在的dbger没法调的。

那个代码是利用了堆栈执行的特点,实际上是个漏洞。如果stack被保护起来,只允许r/w就没戏了。
2004-11-12 22:50
0
雪    币: 253
活跃值: (250)
能力值: ( LV9,RANK:210 )
在线值:
发帖
回帖
粉丝
16
并不是绝对的不能调试,可以到98下去用trw2000来调呀
2004-11-12 23:15
0
游客
登录 | 注册 方可回帖
返回
//