下面的代码由Gary Nebbett写就.Gary Nebbett乃是WINDOWS NT/2000 NATIVE API REFERENCE的作者.乃NT系统一等一的高手.下面就分析一些他的这段代码.
这段代码在PROCESS没有结束前就将启动PROCESS的EXE文件删除了.
int main(int argc, char *argv[])
{
HMODULE module = GetModuleHandle(0);
CHAR buf[MAX_PATH];
GetModuleFileName(module, buf, sizeof buf);
CloseHandle(HANDLE(4));
__asm {
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
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不被删除.) Gary Nebbett果然是WIN系列平台的顶尖高手之一.能写出如此代码.独辟蹊径啊:)
这段代码在PROCESS没有结束前就将启动PROCESS的EXE文件删除了.
int main(int argc, char *argv[])
{
HMODULE module = GetModuleHandle(0);
CHAR buf[MAX_PATH];
GetModuleFileName(module, buf, sizeof buf);
CloseHandle(HANDLE(4));
__asm {
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
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不被删除.) Gary Nebbett果然是WIN系列平台的顶尖高手之一.能写出如此代码.独辟蹊径啊:)
你的这段话我早就看了,
我现在弄不明白DeleteFile的参数究竟是module 呢还是buf?
另外,我的问题还没解决呢?怎么样在程序删除后退出前在调用我的另外一个函数??
{
printf("I'm dieing.\n");
}typedef void PFUN();
void main()
{
int i=0;
PFUN *pmyfun;
HMODULE module = GetModuleHandle(0); CHAR buf[MAX_PATH]; GetModuleFileName(module, buf, sizeof buf); CloseHandle((HANDLE)4);
pmyfun = myfun;
//UnmapViewOfFile(module); __asm {
lea eax, buf
push 0
push 0
push eax
push ExitProcess
push module
push DeleteFile
push UnmapViewOfFile
push pmyfun
ret
}
}
直接把myfun压栈得到的是错误的地址。
更精妙的是,把所需要的位于自己的执行映像中的代码全部压进了栈,其他需要的代码都位于系统DLL中,使得解除映像不丢失代码。
DeleteFile跟buf也就是eax中间还隔了module和ExitProcess,怎么参数会是buf呢?那ExitProcess 的参数是不是module呢?
这里是怎么区分函数与参数的啊?能不能讲详细点?
那几个函数的用户态存根代码中使用这样的指令传递参数的:
push [esp+4]
push [esp+8]
等
只有看过代码才知道那个是参数,哪个是返回地址。
我今天为此浪费了两个多小时,我要被老板骂了。
:-)
我将push pmyfun 放到push ExitProcess 和 push module之间,可是运行后出错。
究竟该怎么放?放哪里?
如果要在删除文件后运行代码,要将该函数的全部代码压入堆栈,而不仅是起始地址。
要是那个函数中没有调用别的函数还有希望,否则算了吧。
代码要反复编译计算,我没有精力试了,对不起。
如果我要在执行这段代码之后能够继续执行这段汇编语句后面的C语句,那么最先push的应该是什么呢?
exitprocess的参数是(eax,0,0),因为是从右->左压栈的
deletefile的参数是module
这参数究竟是怎么给的啊?
另外,我的问题没人回答吗?
就是在删除文件后,怎么样再调用我的另一个函数,执行完那个函数之后才最后退出。
这样究竟该怎么做啊?
非常感谢 repus() 的热情帮助,不过我的问题依然没有解决,那就是:怎么样在删除了执行文件后,调用我的另一个函数,等执行完我那个函数后才退出程序。该怎么去实现呢??另外我想纠正 freebsd_cn(l0v3hx) 的一个个错误:DeleteFile的参数不是modul而是buf的内容即文件名。
非常感谢 repus() 的热情帮助,不过我的问题依然没有解决,那就是:怎么样在删除了执行文件后,调用我的另一个函数,等执行完我那个函数后才退出程序。该怎么去实现呢??另外我想纠正 freebsd_cn(l0v3hx) 的一个个错误:DeleteFile的参数不是modul而是buf的内容即文件名。
push 0
push 0
push eax
push exitprocess
push buf
push deletefile
这样压参数可以吗???
真的是这样,
不信,你可以DEBUG跟踪看看。
我当象你那样认为的,可是错了。因为它的参数偏移量有时是+4有时是+8
我也弄不明白为什么这样。
push 0 ;ExitProcess(0)
push eax ;DeleteFile(buf)
push ExitProcess
push module ;UnmapViewOfFile(module)
push DeleteFile
push UnmapViewOfFile如果你想加进去自己的函数,应该这样 lea eax, buf
push 0 ;ExitProcess(0)
push yourparameter ;yourfunction(yourparamenter)
push ExitProcess
push eax ;DeleteFile(buf)
push yourfunction
push module ;UnmapViewOfFile(module)
push DeleteFile
push UnmapViewOfFile不过,很不幸,由于UnmapViewOfFile的作用,等到yourfunction的时候,进程的内存已经被释放了,地址跳转倒很正常,不过代码已经全没了,你自己可以试试看。另外,还有一点,这些函数都必须是_stdcall类型的,也就是被调用者清理栈中的参数。
kkk16()
ExitProcess 的参数是0
DeleteFile 的参数是eax也就是buf
UnmapViewOfFile 的参数是module
他们都是__stdcall,自己清理堆栈,都用的是
ret 4
当UnmapViewOfFile 执行完时(调用ret 4之后)堆栈如下:
24 0
20 0
16 offset buf
12 address of ExitProcess