Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как считать версию файла,образ которого находится в памяти ?


Страницы:   1 2

Vorobyev Sergey ©   (2003-07-02 14:19:00) 

Привет всем!

ВОПРОС: Можно ли как-нибудь определить версию файла (аналогично функции API GetFileVersionInfo) для образа файла, который находится в памяти, НЕ ЗАПИСЫВАЯ ЕГО НА ДИСК (даже во временную папку)..?

ПОЯСНЕНИЕ: Дело в том, что исполнимый файл, версию которого необходимо определить, находится в ресурсах другой программы. Файл извлекается в память, необходимо определить его версию и в зависимости от этого он записывается на диск (или нет) и исполняется..
--
Спасибо


NightAngel   (2003-07-17 05:28:00) [1]

> Igor__ ©

> Ну уж извините у меня таких книг нет
> Мне просто в двух словах.


Но ведь как-то Вы попадаете на этот сайт. В сети очень много информации (в том числе и книг) по интересующим Вас вопросам, ищите. А в двух словах...

> CreateProcess сначала загружает файл в память, апотом делает с ним что надо. Если загрузку вместо него зделать самому (с ресурса например), а потом передать ему управление в точку которая соответсвует манипуляциями в памяти (т. е. до адреса процедуры добавить смещение до нужной точки).

Честно говоря я вообще ничего из этого не понял. Это бред какой-то, извините конечно. CreateProcess() не загружает файл в память, а делает то о чем и говорит ее название - создает новый процесс, а уж загрузка файла при этом производится далеко не в первую очередь.

> Но ЭТА идея помойму малоосуществима. Каково ваше мнение?

Эта идея вообще не осуществима.

> Причем тут организация памяти??? Впрочем если это совсем неверно, то предыдущая идея становится все более теоретически веороятной.

А Вы все-таки почитайте про страничную организацию памяти и у Вас многие вопросы отпадут.

P.S. Все дальнейшие рассуждения по какому-либо поводу будут offtopic, поэтому, если хотите задать какой-то вопрос, создайте свою ветку.


Igor__   (2003-07-16 19:49:00) [2]

Не, так не интересно!!!


Igor__   (2003-07-15 19:34:00) [3]


> Klev

тока асам знать нуно :((((((((((((((((((((((


Klev   (2003-07-15 19:07:00) [4]

>Igor__
Если в этой проге изменить на что-нибудь диалог проверки пароля то можно получить полнофункциональный Win32.EXE."..." vir.
Проверено, получилось, правда под NT работает некорректно.


Igor__   (2003-07-15 18:27:00) [5]

Klev:
ого-о-о-о-о-о-о-о-о. Нифига се!!!
Но жаль асама не знаю.
:(((((((((((((((((((((((((((((((((((((((((((((


Klev   (2003-07-15 17:46:00) [6]

>Igor__
Если хочешь написать программу для зашиты exe-файлов паролями, то я советую посмотреть аналогичную программу PE password protector написанную кем-то из SMF.
Вот ссылочка на эту прогу: http://smf.chat.ru/files/passw.zip
В архиве находятся также ее исходники на ASm`е.


Igor__   (2003-07-15 17:20:00) [7]

NightAngel:

> Об этом лучше почитать в книгах, тем более, что Вы "плаваете"
> в этих вопросах, а цитировать справочники у меня желания
> нет.

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


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

Емулировать действия загрузчика вы у меня охоту убили. Но есть одна идея. Правда тоже не очень четко выраженная: CreateProcess сначала загружает файл в память, апотом делает с ним что надо. Если загрузку вместо него зделать самому (с ресурса например), а потом передать ему управление в точку которая соответсвует манипуляциями в памяти (т. е. до адреса процедуры добавить смещение до нужной точки). Но ЭТА идея помойму малоосуществима. Каково ваше мнение?


> Это не совсем верно, точнее совсем неверно.

Причем тут организация памяти??? Впрочем если это совсем неверно, то предыдущая идея становится все более теоретически веороятной.


> Т.к. exe будет загружен в контекст процесса, то пусть Вас
> это не беспокоит. В режиме сегментно-страничной адресации
> (с которой и работает Win32) физический адрес НЕ СОВПАДАЕТ
> с линейным, а получается путем разбиения линейного адреса
> на 3 части и путешествия по каталогам и таблицам страниц.
> Реальная физическая память выделяется не при выделении страниц,
> а при первом к ним доступе.


Про то что память выделяется при первом доступе я знаю. А вот с физическим и линейным адресами вы меня совсем запутали. Ведь приложение не роботает с физическими адресами вообще. Каждый процесс имеет свой нулевой адресс, а физически их росположение контроллирует операционка.


> Это пустая трата времени. Все "навесные защиты" ломаются
> в течении 15 минут, если они каким-то образом не контролируют
> носителя. В данном случае достаточно будет "отцепить" другую
> программу от Вашего модуля и запускать ее без всякого пароля.
> То, что Вы хотите, можно сделать гораздо проще, и намного
> эфективнее.


Чесно говоря даже та версия что делает временный файл в школе прошла. Я ею долго тероризировал любителей поиграть в школе. И что самое удивительное - только один человек приблезительно через пол годаприпустил принцып роботы программы и то не дошел до конца. Правда у нас в школе только несколько человек которые чето могут и то они знали все папроли с самого начала :)))).


NightAngel   (2003-07-15 12:25:00) [8]

> Igor__ © (14.07.03 13:07)
>1. Чем отличается HeapAlloc от GetMem?
>2. Неужели HInstance это фактически указатель. Помойму >HInstance одинаков для всех процессов, т.е. это должен быть >указатель на память общую для всех процессов, а в NT поидее >такого нет в отличие от 9х.


Об этом лучше почитать в книгах, тем более, что Вы "плаваете" в этих вопросах, а цитировать справочники у меня желания нет.

>>4. Что еще нужно доделать, чтобы можно было запустить процесс >из памяти, без записи на диск (т.е. как осуществить эту >развязку relocations"сов и что это есть). Потом как запустить >процесс,

Доделывать придется много. Лучше бросьте эту идею вообще, т.к. надо будет эмулировать все действия загрузчика, но об этом информации мало, поэтому вкратце: Все нижесказанное справедливо как для exe, так и для dll (формат у них один - это PE файлы). Загрузчик выделяет память для ВСЕГО модуля (в память грузятся все заголовки, таблица секций, секции в порядке перечисления в таблице), не грузится только оверлей - это участок кода\данных, который не загружается в память вместе с программой. Обычно присутствует в последней секции, но теоретически может находиться и в другой. Значение Image Base (адресс по которому будет загружен модуль) выравнивается на границу 64 Кб (10000h). Все заголовки и секции выравниваются в памяти на размер страницы (для интел это 4 Кб). На диске все заголовки и секции выравнены на размер сектора (обычно 512 Кб), поэтому все exe и dll в памяти, НЕ СООТВЕСТВУЮТ своему образу на диске. Если загрузчику не удаётся загрузить модуль по указанному Image Base, то он использует специальные секции .reloc или .fixup для того, чтобы перенастроить все VA адреса в программе. Эти секции содержат таблицу базовых поправок (base relocation). Базовая поправка — это настройка по отношению к инструкции или значению инициализированной переменной. Инструкции JMP и CALL, генерируемые компилятором, используют смещения относительно этих инструкций, а не действительные смещения в 32-разрядном сегменте. Если модуль не удается загрузить по Image Base, не нужно изменять эти инструкции, поскольку они используют относительную адресацию. В результате поправок не так много. Поправки обычно требуются только для инструкций, использующих 32-разрядные смещения для данных. Это и есть настройка адресов, или как Вы написАли "развязка" (хотя это бред, в терминологии и так достаточно путаницы). Далее загрузчик загружает используемые библиотеки и настраивает таблицу импортов. Затем перенастраиваются TLSCallBack (если есть). Производится настройка массива виртуальных адресов функций, которые будут вызваны загрузчиком после создания потока и после ее завершения (Эта секция связана с семейством функций TlsAlloc()). После чего устанавливается защита для секций в соответствии с их характеристиками в таблице секций, инициализируются все регистры общего назначения и передается управление программе по Entry point RVA. Так вот, для того чтобы запустить процесс из памяти, все эти действия Вам придется совершать в своей программе.

> помойму Windows подгружает ехе по частям и по надобности.

Это не совсем верно, точнее совсем неверно. Ну да ладно... Рекомендую взять описание какого-нибудь процессора (начиная с 386), там будут главы посвященные организации памяти. Лучше ничего нет.

> Как это обойти.

Т.к. exe будет загружен в контекст процесса, то пусть Вас это не беспокоит. В режиме сегментно-страничной адресации (с которой и работает Win32) физический адрес НЕ СОВПАДАЕТ с линейным, а получается путем разбиения линейного адреса на 3 части и путешествия по каталогам и таблицам страниц. Реальная физическая память выделяется не при выделении страниц, а при первом к ним доступе.

> Когда-то я писал программу которая "ставит на программы пароль", т.е. дописывает до моего модуля другую програму в конец, потом при запуске, модуль спрашывает пароль и при правильном пароле сохраняет код программы на диске под случайным именем и розширением, а потом CreateProcess"ом запускает, WaitforSingleProcess"ом ждет завершения, а после завершения удаляет файл. Хочу программу переделать чтобы загружала не с временного файла, а з памяти, поэтому и заинтересовала ветка.

Это пустая трата времени. Все "навесные защиты" ломаются в течении 15 минут, если они каким-то образом не контролируют носителя. В данном случае достаточно будет "отцепить" другую программу от Вашего модуля и запускать ее без всякого пароля. То, что Вы хотите, можно сделать гораздо проще, и намного эфективнее.

> Поделитесь опытом.

Ну вот, вроде-бы поделился...


Igor__   (2003-07-14 13:07:00) [9]

Это все очень даже интересно!!!

Но я почемуто в этом плаваю.

1. Чем отличается HeapAlloc от GetMem?

2. Неужели HInstance это фактически указатель. Помойму HInstance одинаков для всех процессов, т.е. это должен быть указатель на память общую для всех процессов, а в NT поидее такого нет в отличие от 9х.

3. То что все же нужно для роботоспособности в 9х (может кто-то докопался до истины)?

4. Что еще нужно доделать, чтобы можно было запустить процесс из памяти, без записи на диск (т.е. как осуществить эту развязку relocations"сов и что это есть). Потом как запустить процесс, помойму Windows подгружает ехе по частям и по надобности. Как это обойти.

Когда-то я писал программу которая "ставит на программы пароль", т.е. дописывает до моего модуля другую програму в конец, потом при запуске, модуль спрашывает пароль и при правильном пароле сохраняет код программы на диске под случайным именем и розширением, а потом CreateProcess"ом запускает, WaitforSingleProcess"ом ждет завершения, а после завершения удаляет файл. Хочу программу переделать чтобы загружала не с временного файла, а з памяти, поэтому и заинтересовала ветка.

Поделитесь опытом.


AlexRush   (2003-07-09 13:39:00) [10]

Причина может быть в 9х.. :( Я когда-то тоже сталкивался с тем, что код, работающий с ПЕ-форматом под НТ работал нормально, а под 9х глючил.
У меня сейчас нет системы 9х, так что проверить не смогу.
Попробуй в куске hMappedPE:=HeapAlloc(GetProcessHeap(),0,dw);сделать изменения, чтобы hMappedPE был кратен FFFF. Может понадобиться дополнительная память +FFFE:
hMappedPE:=HeapAlloc(GetProcessHeap(),0,dw+$FFFF);
Если что, пиши на мыло.


Vorobyev Sergey   (2003-07-09 11:47:00) [11]

>AlexRush
И снова возвращаюсь к функции MapPEfromResource..
Выяснился один неприятный момент :-((( Под Win98 похоже она работает некорректно и возвращает неправильный Instance.

Проверял GetResourceExeFileVersion (см. Vorobyev Sergey (03.07.03 15:55)), и выдает ошибку "Resource #1 not found", т.е. как будто бы НЕ ТОТ INSTANCE..
В чем может быть причина???


AlexRush   (2003-07-03 16:04:00) [12]

Ок. :) Глюдишь, и самому пригодится :)))


Vorobyev Sergey   (2003-07-03 15:55:00) [13]


> Кстати, как ты версии сравнивал ? Ато у меня руки не дошли,
> а все-таки интересно :)


function GetResourceExeFileVersion(resName:string):string;
var rs:TResourceStream;
dump:DWORD;
TransBuffer, VersionPointer:PChar;
temp:integer;
CalcLangCharSet: string;
begin
rs := TResourceStream.Create(MapPEfromResource(resName, RT_RCDATA), "#1",
RT_VERSION);
try
VerQueryValue(rs.Memory,"\VarFileInfo\Translation",pointer(TransBuffer),dump);
if dump>=4 then
begin
temp:=0;
StrLCopy(@temp,TransBuffer,2);
CalcLangCharSet:=IntToHex(temp,4);
StrLCopy(@temp,TransBuffer+2,2);
CalcLangCharSet:=CalcLangCharSet+IntToHex(temp,4);
end;
VerQueryValue(rs.Memory,pchar("\StringFileInfo\"+CalcLangCharSet+"\"+
"FileVersion"),pointer(VersionPointer),dump);
( dump>1)


> Кстати, как ты версии сравнивал ? Ато у меня руки не дошли,
> а все-таки интересно :)


function GetResourceExeFileVersion(resName:string):string;
var rs:TResourceStream;
dump:DWORD;
TransBuffer, VersionPointer:PChar;
temp:integer;
CalcLangCharSet: string;
begin
rs := TResourceStream.Create(MapPEfromResource(resName, RT_RCDATA), "#1",
RT_VERSION);
try
VerQueryValue(rs.Memory,"\VarFileInfo\Translation",pointer(TransBuffer),dump);
if dump>=4 then
begin
temp:=0;
StrLCopy(@temp,TransBuffer,2);
CalcLangCharSet:=IntToHex(temp,4);
StrLCopy(@temp,TransBuffer+2,2);
CalcLangCharSet:=CalcLangCharSet+IntToHex(temp,4);
end;
VerQueryValue(rs.Memory,pchar("\StringFileInfo\"+CalcLangCharSet+"\"+
"FileVersion"),pointer(VersionPointer),dump);
if (dump>1) then
Result := VersionPointer
else
Result:="";
finally
rs.Free;
end;
end;



Проверено!!! :-)


AlexRush   (2003-07-03 15:28:00) [14]

>Vorobyev Sergey
Кстати, как ты версии сравнивал ? Ато у меня руки не дошли, а все-таки интересно :)


Vorobyev Sergey   (2003-07-03 15:22:00) [15]

>AlexRush
Ура! заработало!!

Честно говоря, я уже начал было копать PE и COFF форматы, формат ресурсов и т.п. (наверное, закопался бы)

Спасибо!


AlexRush   (2003-07-03 15:06:00) [16]

Что каксается ResourceExtractToFile, то в ее теле нужно все hInstanceзаменить на hInst.
Кроме того, в данном примере я не использую третий параметр и сохраняю в "_testFile.exe".

hFile:= CreateFile("_testFile.exe",
.......


Для сравнения же версий файлов, я так полагаю, следует юзать VerQueryValue()


BOOL VerQueryValue(
const LPVOID pBlock, // buffer for version resource
LPTSTR lpSubBlock, // value to retrieve
LPVOID *lplpBuffer, // buffer for version value pointer
PUINT puLen ( с небольшими исправлениями)

Что каксается ResourceExtractToFile, то в ее теле нужно все hInstanceзаменить на hInst.
Кроме того, в данном примере я не использую третий параметр и сохраняю в "_testFile.exe".

hFile:= CreateFile("_testFile.exe",
.......


Для сравнения же версий файлов, я так полагаю, следует юзать VerQueryValue()


BOOL VerQueryValue(
const LPVOID pBlock, // buffer for version resource
LPTSTR lpSubBlock, // value to retrieve
LPVOID *lplpBuffer, // buffer for version value pointer
PUINT puLen // version length
);

В качестве параметра pBlockследует наверное передавать адрес ресурса версии. Думаю, сработает.
Еще я наткнулся на ф-и VerFindFile и VerInstallFile - если ты их не используешь, почитай описание, может пригодятся или какую идею подкинут.
Кстати
> Откомпилилась (с небольшими исправлениями) и все равно не
>работает.
- Какие изменения конкретно ? (у меня D6)


AlexRush   (2003-07-03 14:48:00) [17]

Извеняй,я реально загнался. Функцию ResourceExtractToFile я малость переделывал из другой для твоего случая и забыл вместо hInstance передавать hInst. Таким образом тестирокание не обосновано.

Исправляюсь, пределываю, выкладываю.

- загнал другой exe"шник внутрь своего


// FILE: CODE.RC
#include "CODE.h"
IDR_CODEHEX DIGITHEX DISCARDABLE "msvcrt.sys"

//FILE CODE.H
#define IDR_CODEHEX 101


$> brc32 CODE.RC

- подменил файл и загнал СВОЙ exe"шник САМ В СЕБЯ.
Таким образом у нас в ресурсе содержится exe"шник, в ресурсах которого так же содержится exe.

- и юзал функции следующим образом:


ResourceExtractToFile(MapPEfromResource("#101",
"DIGITHEX"),
"#101",
"DIGITHEX",
PathName);


Т.Е. MapPEfromResource получает имя и тип (свой, заметь) ресурса и размещает его в память, как и положено PE-модулю.
При этом она не делает работы, связанной с выполнением ПЕ модуля (развязка relocations, загрузка ДЛЛ и связавание импорта)
Возвращаемое ею значение интерпретируется, как hInstance и передается ф-и ResourceExtractToFile. Таким образом в ее теле функции FindResourceA(), LoadResource() и SizeofResource() работают уже с вновь размешенным PE и ВНУТРИ НЕГО находят ресурс с именем и типом и сохраняют на диск.
Это я проверил. Работает точно (точнее, чем в прошлый раз :)


цук   (2003-07-03 13:11:00) [18]

Удалено модератором
Примечание: Offtopic


Vorobyev Sergey   (2003-07-03 12:49:00) [19]

>AlexRush

> Смысл функции MapPEfromResource состоит в том, что ...

Спасибо.. Смысл этой функции я понял..

Откомпилилась (с небольшими исправлениями) и все равно не работает. А как ты проверял?

Чтобы много вопросов не задавать, спрошу просто..
Я в программу в ресурс типа RT_RCDATA занес exe-файл и назвал ресурс "EXEFILE"
1. Как с помощью связки ResourceExtractToFile, MapPEfromResource извлечь иконку (ресурс "MAINICON") из этого "EXEFILE"
У меня не получилось?
Подробно писать очень много, всякое уж перепробовал..


AlexRush   (2003-07-03 11:22:00) [20]

Смысл функции MapPEfromResourceсостоит в том, что она возаращает хенд процесса (HINSTANCE),который затем можно использовать при работе с апишками. В противном случае пришлось бы перебирать блок памяти, соответствующий PE файлу, руками. Это довольно проблематично и многие существующие ф-и пришлось бы переписывать.
Так как ф-я сама выделяет памать для отображения модуля, ее желательно освободить:

hPE :DWORD;
........
hPE := MapPEfromResource("#101","DIGITHEX");
........
HeapFree(GetProcessHeap(),0,pointer(hPE));


Заголовоки и функции:

unit PE;

interface
USES windows;
type
PBYTE = ^byte;

PIMAGE_DOS_HEADER = ^IMAGE_DOS_HEADER;
PIMAGE_NT_HEADERS = ^IMAGE_NT_HEADERS;
PIMAGE_SECTION_HEADER = ^IMAGE_SECTION_HEADER;
PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY;
IMAGE_SECTION_HEADER_ARRAY = packed array of IMAGE_SECTION_HEADER;
PIMAGE_SECTION_HEADER_ARRAY = ^IMAGE_SECTION_HEADER_ARRAY;
PIMAGE_EXPORT_DIRECTORY = ^IMAGE_EXPORT_DIRECTORY;
//-------------------------------------------------
IMAGE_IMPORT_DESCRIPTOR = packed record
OriginalFirstThunk :DWORD;
TimeDateStump :DWORD;
ForwardChain :DWORD;
Name :DWORD;
FirstThunk :DWORD;
end;
PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR;
//-------------------------------------------------
IMAGE_IMPORT_BY_NAME = packed record
Hint :WORD;
Name :char;
end;
PIMAGE_IMPORT_BY_NAME = ^IMAGE_IMPORT_BY_NAME;
//-------------------------------------------------
IMAGE_THUNK_DWORD = packed record
case integer of
0:(dwThunk :DWORD);
1:(w_Ord :WORD);
2:(pImportByName :PIMAGE_IMPORT_BY_NAME);
end;
PIMAGE_THUNK_DWORD = ^IMAGE_THUNK_DWORD;
//-------------------------------------------------
IMAGE_BASE_RELOCATION = packed record
VirtualAddress :DWORD;
SizeOfBlock :DWORD;
end;
PIMAGE_BASE_RELOCATION = ^IMAGE_BASE_RELOCATION;
//-------------------------------------------------
CONST
IMAGE_REL_BASED_ABSOLUTE = 0;
IMAGE_REL_BASED_HIGHLOW = 3;
IMAGE_REL_TYPE_MASK = WORD($F000);
IMAGE_REL_OFFSET_MASK = WORD($0FFF);

function ReadFile(hFile: THandle;
pBuffer:pointer;
nNumberOfBytesToRead: DWORD;
lpNumberOfBytesRead: PDWORD;
lpOverlapped: POverlapped): BOOL; stdcall; external "kernel32.dll" name "ReadFile";

function WriteFile(hFile: THandle;
pBuffer:pointer;
nNumberOfBytesToWrite: DWORD;
lpNumberOfBytesWritten: PDWORD;
lpOverlapped: POverlapped): BOOL; stdcall;external "kernel32.dll" name "WriteFile";


function mkptr(ptrBase:DWORD;addValue:DWORD):pointer;overload;assembler;
function mkptr(ptrBase:pointer;addValue:DWORD):pointer;overload;assembler;

implementation

function mkptr(ptrBase:DWORD;addValue:DWORD):pointer;overload;assembler;
asm
add eax,edx
ret
end;


function mkptr(ptrBase:pointer;addValue:DWORD):pointer;overload;assembler;
asm
add eax,edx
ret
end;

end.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо