Форум: "WinAPI";
Текущий архив: 2002.02.18;
Скачать: [xml.tar.bz2];
ВнизКакой ресурс в NT жестко ассоциирован с хэндлом со значением 4 ? Найти похожие ветки
← →
paul_shmakov (2001-11-07 20:49) [12]конечно я очень любопытный :) инета у меня дома не было, а как
пример работал я забыл. поэтому пришлось свой написать под nt.
после недолгих экспериментов все оказалось достаточно просто:
pe-загрузчик создает адресное пространство для процесса, а затем
проецирует туда exe-шник (т.е. создает объект ядра memory mapped file
(CreateFileMapping), проецирует mmf на адресное пространство
(MapViewOfFile), начиная с адреса image base, указанного в
pe-заголовке). как раз его (mmf) хэндл со значением 4 и находится
в таблице хэндлов каждого процесса в winnt.
итак, что нам мешает удалить исполняемый файл? а мешает нам то,
что файл как раз спроецирован на адресное пространство процесса.
решение казалось бы на ладони: убираем проекцию и закрывыем хэндл
объекта mmf, после чего можно удалить файл:
UnmapViewOfFile(GetModuleHandle(0));
CloseHandle(4);
DeleteFile(filename);
или тоже самое на асме
push 0
call GetModuleHandle
push eax
call UnmapViewOfFile
push 4
call CloseHandle
lea eax, filename
push eax
call DeleteFile
но появляется проблема: после вызова UnmapViewOfFile виртуальные
адреса памяти, по которым находилась проекция, освободятся и,
когда поток перейдет к выполнению следующей команды (вызов
DeleteFile) произойдет нарушение доступа.
но направление движения правильное! только осуществлять эти
вызовы нужно несколько иначе. поместим все в стек потока (уж
стек никуда не денется до завершения работы потока).
поместим туда и адреса функций и их параметры. кроме того
вызовем после удаления файла ExitProcess, потому что если после
удаления файла (т.е. вызова DeleteFile) поток вернется опять
же в нашу функцию, снова произойдет нарушение доступа.
push 0
lea eax, szFileName
push eax
push pExitProcess
push 4
push pDeleteFile
push hInstance
push pCloseHandle
push pUnmapViewOfFile
ret
как это работает:
1) команда ret берет из стека двойное слово с вершины
стека и передает управление по этому адресу. т.о. управление
переходит на функцию UnmapViewOfFile.
2) UnmapViewOfFile принимает один параметр (hInstance), но
кроме этого параметра в стек нужно запихнуть и адрес возврата.
поэтому в стек помещается адрес на функцию CloseHandle.
3) Отработав, UnmapViewOfFile удаляет из стека свой единственный
параметр и передает управление на CloseHandle. эта функция
тоже принимает один параметр (4), и ей также нужен в стеке
адрес возврата (теперь это указатель на DeleteFile).
4) далее аналогично.
следует заметить, что после вызова ExitProcess все потоки
процесса завершаются, и о никакой передачи управления далее
по стеку и речи быть не может.
резюме: этот способ использует недокументированные особенности
winnt 4.0 и работать будет, скорее всего, только в этой версии
виндов. тем не менее, я не вижу никаких ошибок в этом коде -
все совершенно законно. правда, теоритически возможна ситуация,
когда после вызовов CloseHandle и UnmapViewOfFile система не успеет
освободить файл, и вызов DeleteFile потерпит неудачу (хотя мне
этого добиться не удалось - все работает как часы).
и еще одно замечание. неважно, что вызвать первым - CloseHandle
или UnmapViewOfFile - это независимые между собой вызовы.
главное - вызвать и то, и другое :) независимы они потому что
MapViewOfFile увеличивает reference count объекта mmf. ну а
UnmapViewOfFile, соответственно, его уменьшает. поэтому
CloseHandle можно вызвать в любой момент.
вот небольшой пример на c++, реализующий подход.
/*
test.cpp
deletes itself. winnt only
bcc32 -tW -B test.cpp
*/
#include <windows.h>
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
char szFileName[MAX_PATH];
GetModuleFileName(GetModuleHandle(0), szFileName, MAX_PATH);
HMODULE hkrnl = GetModuleHandle("kernel32.dll");
void* pUnmapViewOfFile = GetProcAddress(hkrnl, "UnmapViewOfFile");
void* pDeleteFile = GetProcAddress(hkrnl, "DeleteFileA");
void* pExitProcess = GetProcAddress(hkrnl, "ExitProcess");
void* pCloseHandle = GetProcAddress(hkrnl, "CloseHandle");
unsigned hInstance = (unsigned)GetModuleHandle(0);
asm {
push 0
lea eax, szFileName
push eax
push pExitProcess
push 4
push pDeleteFile
push hInstance
push pCloseHandle
push pUnmapViewOfFile
ret
};
return 0; /* never get here */
}
p.s. насчет win9x ничего сказать не могу, т.к. у меня ее нет.
Страницы: 1 вся ветка
Форум: "WinAPI";
Текущий архив: 2002.02.18;
Скачать: [xml.tar.bz2];
Память: 0.46 MB
Время: 0.004 c