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
 
жду ответа.
			  
			
			
			
		 |