Bers, продолжим здесь.
baratorch Wrote:Berserker Wrote:На мой взгляд, указанная тобой, Бара, проверка, неэффективна. Мало ли из какого кода какого модуля вызывается запись патча? Из ЕРМ? Из сгенерированного в оперативной памяти обработчика? Из модуля, который использует функционал другого?
Patcher := Core.GlobalPatcher.CreateInstance(pchar(GetUniquePatchName(BinPatchSource)));
Я создавал по экземпляру патчера для каждого файла-заплатки под уникальным именем и тут же пробовал через этот объект вносить изменения в цикле:
Patcher.Write(cardinal(Patch.Addr), cardinal(@Patch.Bytes), Patch.NumBytes, CODE_PATCH);
В итоге ошибки и, как следствие, вылеты.
Берс, я хочу чтобы у тебя там все работало с патчером.
Но что ты предлагаешь, убрать эту проверку совсем?
Мне это сделать не сложно. Я задавал вопросы, чтобы понять, можно ли решить твою проблему не трогая патчер, но ситуацию ты не прояснил.
Я пока не представляю себе случая когда модулю нужно создать патчер_инстанс, но не писать патч, а модулю не создававшему использовать чужой патчер_инстанс чтобы создавать патч; и чтобы требуемую задачу нелзя было полностью решить с помощью того что есть сейчас.
Покажи мне конкретный пример (из твоих слов о цикле и заплатках мне ничего не понятно).
Если убрать эту проверку, то (как мне кажется) теряется вообще смысл в классе PatcherInstance. И как тогда отслеживать авторов патчей в логе и дампе (одна из важнейших фич патчера), если автором патча может быть кто угодно, вместо обозначенного?
Quote:Patcher := Core.GlobalPatcher.CreateInstance(pchar(GetUniquePatchName(BinPatchSource)));
Я создавал по экземпляру патчера для каждого файла-заплатки под уникальным именем и тут же пробовал через этот объект вносить изменения в цикле:
Patcher.Write(cardinal(Patch.Addr), cardinal(@Patch.Bytes), Patch.NumBytes, CODE_PATCH);
Вот я написанное понимаю так, что и инстанция и патч через эту инстанцию создаются в одном куске кода, т.е. без вариантов в одном модуле (pe-файле... dll/exe).
Поэтому та проверка (на идейном плане), считаю, не может быть помехой (разве что в ее реализации косяки).
вот код из ХД:
Code:
void LoadBinPatch(char* file_name)
{
DWORD fr;
_dword_ patches_count = 0;
_dword_ patch_size = 0;
_byte_ patch_data[2048];
_ptr_ address = 0;
HANDLE hFile = INVALID_HANDLE_VALUE;
hFile = CreateFile(file_name, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
PatcherInstance* _PIbin = _P->CreateInstance(Base::GetShortFileName(file_name));
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
if (ReadFile(hFile, (LPVOID)&patches_count, 4, &fr, NULL))
for (int i = 0; i < patches_count; i++)
if (ReadFile(hFile, (LPVOID)&address, 4, &fr, NULL))
if (ReadFile(hFile, (LPVOID)&patch_size, 4, &fr, NULL))
{
if (patch_size > 2048) BREAKPOINT;
if (ReadFile(hFile, (LPVOID)&patch_data, patch_size, &fr, NULL))
{
_PIbin->Write(address, (_ptr_)patch_data, patch_size);
}
}
CloseHandle(hFile);
}
}
...
void LoadBinPatches(char* dir)
{
WIN32_FIND_DATA file_find_data;
HANDLE h_search;
BOOL finished = FALSE;
Base::dir_set(dir);
h_search = FindFirstFile("*.bin", &file_find_data);
if (h_search == INVALID_HANDLE_VALUE)
{
Base::dir_restore();
return;
}
while (!finished)
{
//////////////////////////////////////
LoadBinPatch(file_find_data.cFileName);
//////////////////////////////////////
if (!FindNextFile(h_search, &file_find_data))
if (GetLastError() == ERROR_NO_MORE_FILES)
finished = TRUE;
else
{
FindClose(h_search);
Base::dir_restore();
return;
}
}
FindClose(h_search);
Base::dir_restore();
}
в цикле вызывается создание инстанций для каждой заплатки и запись патча этой заплатки через созданную инстанцию.
по-моему то же самое. все работает.
...
Я понял в чем дело.
Нужно заменить
Patcher.Write(cardinal(Patch.Addr), cardinal(@Patch.Bytes), Patch.NumBytes, CODE_PATCH);
на
Patcher.Write(cardinal(Patch.Addr), cardinal(@Patch.Bytes), Patch.NumBytes, DATA_PATCH);
Это не очевидно, но я объясню почему.
Я понимаю что, практически все сочиняемые пачти подразумевают содержание кода. Однако CODE_PATCH в Методе Write
означает не то что 'мы пишем код', а то что данные по адресу @Patch.Bytes будут восприниматься как код.
Возмем пример из ченджлога к патчеру 2.5.
Допустим мы хотим поставить патч 0x639C40: call 0x447799.
В бин-файле это будет записано в прямом виде: 0x639C40, 5, E8 54 DB E0 FF
после считывания в Patch.Bytes будет E8 54 DB E0 FF
но ведь @Patch.Bytes не равен 0x639C40!!!
а значит если мы подразумеваем что по адресу @Patch.Bytes код, а не данные, то E8 54 DB E0 FF будет вызывать не 0x447799, а функцию заданную адресом относительным к @Patch.Bytes.
Ну вот представь, что мы процессору передали на выполнение адрес @Patch.Bytes: будет вызвана функция не 0x447799, а совершенно левая.
***
Еще раз повторю вопрос: что выдает лог патчера?
создаем рядом с patcher_x86.dll - patcher_x86.ini c записью Logging = 1
и после установки всех патчей вызываем Patcher::SaveLog(char* file_name).
если в логе отсутствуют записи
ERROR! Can not create ... at ... (...): Wrong Patcher Instance!
то проверка на верный модуль ни при чем, а дело в CODE_PATCH
жду ответа.
|