Как открыть на чтение запущенный exe (C++ Builder, Delphi) и вообще любой заблокированный файл

2010-11-02 papirosnik C++ Builder

При программировании в среде C++ Builder и/или Delphi программисты иногда сталкиваются со следующей проблемой: при попытке открыть при помощи Reset заблокированный системой файл (например запущенный exe-шник) программа валится с ошибкой. Наиболее типичной является необходимость открыть сам исполняемый файл программы, чтобы прочитать какие-то данные из него. Такая ситуация часто возникает при реализации каких-то своих собственных защит от взлома, установки ограничений на триальный период и т.п. Можно какие-то сведения хранить в ресурсах — но тогда они легко доступны для чтения и редактирования с помощью любого редактора  ресурсов. Более изощрённые предпринимают попытки модифицировать сам код в exe-файле, хранить какие-то значения в теле exe-файла. И тогда начинаются танцы с бубном.

Наиболее очевидное (кажущееся) решение — скопировать этот файл в другой временный и работать с ним. Так советуют поступать почти все авторы, которые выкладывают свои решения на страницах рунета. Но чтобы скопировать файл, надо опять же открыть его при помощи Reset. Замкнутый круг. И тут вспоминают про WinAPI, чтобы скопировать файл во временный каталог, и уже с временной копией работают как угодно. Например при помощи CopyFile(PChar(ParamStr(0)), PChar('Новый_путь' +ExtractFileName(ParamStr(0))), True); Совершенно при этом упуская из виду, что истина уже где-то рядом…
Например, взгляните на код, котрый предлагается в качестве типичного решения:
sNewDir:='C:Programm FilesMyFolder;
sNewPath:=sNewDir+'';
sNewFile:=sNewPath+ExtractFileName(Application.ExeName);
if FileExists(sNewFile) then DeleteFile(sNewFile);
CopyFile(PChar(Application.ExeName),PChar(sNewFile),FALSE);

Или вот, посмотрите, сколько нагородили "умных" советов на таком уважаемом форуме программистов, как Vingrad: http://forum.vingrad.ru/forum/topic-72351.html
 Уже додумались до того, что раз экзешник нельзя открыть при помощи Reset, то его нужно переименовать при помощи WinAPI — и затем открыть. Но никто почему-то не задумывается, а почему не открывает файл для чтения процедура Reset? В то время как WinAPI таким недостатком не страдает… позволяет копировать и переименовывать запущенный экзешник. Так почему же так происходит?
Правильно сформулированный вопрос — это уже половина ответа. Который надо искать в самой процедуре Reset. А что мы про неё знаем? Тo что она в качестве параметра получает файловую переменную (переменную типа file). А что это за тип такой? Откроем справку и увидим, что это обычная запись (record), в коротой содержится несколько полей, в том числе и FileMode. А что это за режим файла? Да вот он как раз и показывает, что это режим открытия файла: 
0 Read only
1 Write only
 2 Read/Write (По умолчанию)

Вот где собака зарыта. Reset пытается открыть файл как для чтения, так и записи. Но мы же хотим только прочитать, поэтому для решения задачи чтения заблокированного файла достаточно перед вызвовом Reset(F) поставить F.FileMode := 0;
Вот так — всего одна срочка избавляет от необходимости совершенно дикого копирования при помощи WinAPI во временный каталог и т.п. жутким вещам, которые приходится городить начинающим программистам, нежелающим мыслить рационально:)

Файловая система,

10 комментариев to “Как открыть на чтение запущенный exe (C++ Builder, Delphi) и вообще любой заблокированный файл”


Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Powered by WordPress. Designed by elogi.