"Окольцовывание" программ.


Общая идея:

Для изучения миграций животных их "окольцовывают" (т.е. прикрепляют к телу зверя метку, обычно в виде кольца). Ну и делают записи, что в таком-то районе животное было окольцовано, а в каком-то другом районе его потом нашли с этой меткой.

Примерно то же самое делают с людьми, когда выдают им паспорта, и заставляют делать регистрацию... :-)

Если провести аналогии с живой природой, то программа (совокупность всех её копий) - это будет вид, а конкретный экземпляр программы - особь данного вида.

Этой аналогии можно посвятить отдельную большую статью (ареал обитания, выживание и распространение вида, и даже самопожертвование отдельной особи ради выживания вида). Здесь рассмотрим только лишь ПУТИ распространения программ.

Идея в том, чтобы проследить как распространяется от компьютера к компьютеру конкретный экземпляр программы.

Мне представляется очень интересным отследить эти пути распространения, как то: Иванов скопировал программу Петрову, Петров - Сидорову, а Сидоров - Рабиновичу.

В большинстве случаев с распространением программ всё просто: программа скачивается с сайта или устанавливается с CD-диска и живёт на компьютере до перестановки системы. Эти случаи не представляют особого интереса, тут всё понятно.

Нам интересны случаи: "О! какая классная программа - скопируй мне!", когда программа передаётся из рук в руки или кочует по локальной сети или электронной почте.

Также любопытно отследить как кочуют вирусы и трояны.


Как это технически реализовано:

Где хранить информацию о перемещениях программы? Реестр по понятным причинам не подходит. Конфигурационные файлы: не всегда их могут скопировать, да и это представляется мне не лучший вариант (хотя наверное самый простой). Поэтому, как самый безотказный вариант, - данные будем хранить прямо в екзешнике!

Как известо, в конец exe-файла можно дописать всё что угодно, и он будет продолжать работать как ни в чём не бывало.

Информацию о том, на каких машинах её запускали программа будет дописывать себе в конец exe-файла. Эта информация следующая: имя компьютера, имя пользователя, дата и время.

Каждый запуск программа читает из себя последнюю запись и сравнивает имя машины (имя машины, на которой она сейчас запущена, и то, которое есть в записи). Если оно совпадает, значит в прошлый раз программу запускали с этого же компьютера. Если не совпадает, то программа дописывает себе в конец ещё одну запись, содержащую имя компьютера, имя пользователя, дата и время запуска.

"Поймав" такую окольцованную программу можно прочитать записи о том, сколько она прошла компьютеров и в какое время, и составить некоторое представление о том, как же она распространяется в информационном пространстве.


Реализация:

Для реализации используем Borland Delphi и библиотеку KOL. (можно сделать всё на чистом WinAPI, но на KOL всё это делать гораздо удобнее).

Читать из запущенного екзешника можно без проблем.

//чтение
AssignFile(F,paramstr(0));
FileMode := 0; //доступ к файлу только для чтения
Reset(F,1);
Seek(F,FileSize);
repeat
  BlockRead(F,Buf,SizeOf(Buf),NumRead);
  s:=s+copy(String(buf),1,NumRead);
until NumRead<SizeOf(Buf);
CloseFile(F);

FileSize - это константа, которая содержит размер собственно exe-файла, без всяких дополнительных записей. Именно с этого места и до конца файла программа начинает читать записи. В каждом конкретном случае нужно исправить эту константу, посмотрев размер только что откомпилированного файла.

С записью - несколько сложнее. Для этого используем следующий трюк: запущенный файл в Windows нельзя удалить или изменить, но можно переименовать или переместить.

В итоге получаем следующий алгоритм: - переименовываем свой файл - создаём новый файл, изменённый, с прежним именем - запускаем новый файл, с параметром чтобы удалить старый

//переименовываем свой файл
MoveFile(PChar(paramstr(0)),PChar(paramstr(0)+'.old'));

//создаём новый файл, с прежним именем
CopyFile(PChar(paramstr(0)+'.old'),PChar(paramstr(0)),false);

//изменяем его
AssignFile(F2,paramstr(0));
Append(F2);
Write(F2,
	BeginSig+
	GetComputerName+
	MiddleSig+
	GetUserName+
	EndSig+
	DateTime2StrShort(Now)
	);
CloseFile(F2);

//запускаем новый файл, с параметром чтобы удалить старый
ExecuteWait(paramstr(0),'"/del"'+' '+'"'+paramstr(0)+'.old'+'"','',0,0,0);

скачать пример

комментарии


(L)CopyLeft Siliks, oct 2008.     ICQ:0x426D98C     E-Mail: siliks(собака)yandex.ru