Перейти к содержимому
Korean Random
Pavel3333

XFW Native - долгая загрузка

Рекомендуемые сообщения

Клиент с XFW Native грузится в 3 раза дольше, чем без него. По предложению @GPCracker, это связано с регулярным поиском сигнатур функций питона в памяти.

 

Есть предложение от @GPCracker

Цитата

а нельзя ли эти точки закешировать в пределах неизменности контрольной суммы exe клиента и значимых dll?

 

То есть при каждом патче пройтись по exe'шнику танков и записать смещения функций питона. Мне кажется, это очень разумно и будет намного быстрее по времени загрузки, чем каждый раз сканировать память клиента на предмет нахождения сигнатур функций.

  • Нравится 2

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
18 minutes ago, Pavel3333 said:

То есть при каждом патче пройтись по exe'шнику танков и записать смещения функций питона. Мне кажется, это очень разумно и будет намного быстрее по времени загрузки, чем каждый раз сканировать память клиента на предмет нахождения сигнатур функций.

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

  • Нравится 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
(изменено)
6 минут назад, GPCracker сказал:

вслепую

Не совсем вслепую, при совпадении хэшей exe'шника танков

не совпадает - пофиг, пляшем от регулярного поиска сигнатур по шаблону

@sirmax, @Mixaill?

--------------

Надо найти точку входа главной питоновской функции и уже от нее считать смещения. Или, если они все располагаются непоследовательно, как предложил @GPCracker, запоминать смещения в памяти танков и искать сигну по шаблону уже в области этих смещений

Изменено пользователем Pavel3333

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
(изменено)
21 minutes ago, Pavel3333 said:

Не совсем вслепую, при совпадении хэшей exe'шника танков

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

В любом случае, кастуем сюда @Mixaill, ибо именно он стоит за коммитами в тот самый репозиторий.

21 minutes ago, Pavel3333 said:

Надо найти точку входа главной питоновской функции и уже от нее считать смещения.

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

Изменено пользователем GPCracker
  • Нравится 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Прежде чем чего-то советовать хотелось бы мельком увидеть как реализован поиск сигнатур сейчас.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 minute ago, StranikS_Scan said:

Прежде чем чего-то советовать хотелось бы мельком увидеть как реализован поиск сигнатур сейчас.

А в чем собственно проблема? Репозиторий лежит здесь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 минут назад, GPCracker сказал:

Существование таких вещей как таблицы для CheatEngine и ArtMoney явно подтверждает тот факт, что адреса большинства переменных в памяти не изменяются между запусками приложения, однако в случае с динамическим распределением памяти это может не прокатить.

 

Мы же ведем речь об импортах функций, экспорт которых просто убрали из exe. Там должны быть статичные адреса в пределах одной сборки exe.

Только что, GPCracker сказал:

А в чем собственно проблема? Репозиторий лежит здесь.

 

Ну конечно проблем нет. Это как сослаться на библиотеку. Она же стоит и книг там много и вход свободный. Я не разбираюсь что там к чему. Мне нужен конкретный модуль.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@GPCracker @StranikS_Scan вот на примере helper.c:

DWORD WOTPYTHON_FindFunction(DWORD startpos, DWORD endpos, DWORD* curpos, const char* pattern, const char* mask)
{
    DWORD pos;

    for (pos=(*curpos); pos < endpos; pos++)
    {
        if (WOTPYTHON_DataCompare((char*)pos, pattern, mask))
        {
            (*curpos) = pos;
            return pos;
        }
    }

    for (pos = startpos; pos < (*curpos); pos++)
    {
        if (WOTPYTHON_DataCompare((char*)pos, pattern, mask))
        {
            (*curpos) = pos;
            return pos;
        }
    }

    (*curpos) = startpos;
    return 0;
}

То есть задается область памяти (от void* startpos до void* endpos), в ней байт за байтом считываются блоки данных и сверяются по маске.

 

 

fix_winapi.c

FARPROC WINAPI GetProcAddress_libpython(HMODULE hModule, LPCSTR lpProcName)
{
    FARPROC ret = NULL;
    if(hModule==PyWin_DLLhModule)
    {
        ret = (FARPROC)WOTPYTHON_GetRealAddress(lpProcName);       
        if (ret != NULL)
        {
            return ret;
        }
    }

    return GetProcAddress_real(hModule, lpProcName);
}

 

Ищется адрес python27.lib. Не нашли - ищем во ВСЕЙ памяти процесса.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
5 minutes ago, StranikS_Scan said:

Мы же ведем речь об импортах функций, экспорт которых просто убрали из exe. Там должны быть статичные адреса в пределах одной сборки exe.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
(изменено)

При сборке порядок поиска выставляется так, чтобы был только один проход по памяти Worldoftanks.exe. Но так как порядок линковки объектных файлов в MSVC недетерминирован, то довольно часто случается так, что этот порядок сбивается, и при поиске каждой сигнатуры приходится пролопачивать значительно большую часть памяти процесса.

 

Как костыль можно просто перебилдить библиотеку, но более верное решение, как тут уже отметили, сейвить результаты в какой-то файловый кэш.

Изменено пользователем Mixaill

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
51 minutes ago, StranikS_Scan said:

Мне нужен конкретный модуль.

Ну так бы сразу и сказал. А то я уж было подумал, что ты не знаешь про репозиторий :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
(изменено)

@Mixaill кэш можно реализовать, как понимаю, в виде "сигнатура - позиция, по которой она последний раз была найдена".

 

При дальнейших запусках клиента смотреть в кэш. Если не совпало - надо делать по старинке.

Изменено пользователем Pavel3333

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 minute ago, Pavel3333 said:

При дальнейших запусках клиента смотреть в кэш. Если не совпало - надо делать по старинке.

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

3 minutes ago, Pavel3333 said:

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

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

  • Нравится 1

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
(изменено)
Только что, Pavel3333 сказал:

@Mixaill кэш можно реализовать, как понимаю, в виде "сигнатура - позиция, по которой она найдена".

 

Поддержу. Нужен однократный алгоритм поиска всех адресов исключительно с однократным прогоном по памяти. С кэшированием адресов в файл. В результате с одной стороны все последующие загрузки клиента будут без задержек, а с другой стороны - время поиска будет меньше сейчас, так как действительно многократный повторный поиск с нуля - жрёт кучу времени.

 

Я код посмотрел, я не специалист, но мне кажется если если сравниваться будут не Char, а Byte, то будет быстрее. Но я в си не рублю совсем потому могу ошибаться.

 

И еще меня удивило что там чуть ли не на каждый байт памяти игры вызывается функция сравнения с сигнатурой WOTPYTHON_DataCompare . Это если 50 Мб скажем игры, то 50 млн вызовов.

Изменено пользователем StranikS_Scan

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
2 минуты назад, StranikS_Scan сказал:

но мне кажется если если сравниваться будут не Char, а Byte, то будет быстрее

а что char, что byte - это одно и то же. Самый быстрый тип байта в Си - это ЕМНИП unsigned char, он же uint8_t

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Только что, Pavel3333 сказал:

а что char, что byte - это одно и то же. Самый быстрый тип байта в Си - это ЕМНИП unsigned char, он же uint8_t

 

Там нет разницы, там типа char = uint8_t прописано?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
5 минут назад, StranikS_Scan сказал:

Это если 50 Мб скажем игры, то 50 млн вызовов.

Должно быть заинлайнено при текущих флагах, но ок, пропишу тут явно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 minute ago, Pavel3333 said:

а что char, что byte - это одно и то же. Самый быстрый тип байта в Си - это ЕМНИП unsigned char, он же uint8_t

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

@StranikS_Scan нет, наоборот, прописано следующее:

typedef unsigned char      uint8_t;

самый быстрый тип байта - uint_fast8_t, тоже определен как unsigned char:

typedef unsigned char      uint_fast8_t;

Подробнее - в stdint.h (хедер, использующий его - iostream)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Только что, GPCracker сказал:

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

 

Вот. Я когда изучал и потом сам писал и юзал поисковики адресов в ОЗУ, правда на ОbPas, придерживался двух принципов

- ни каких промежуточных вызовов и обращений куда-то там в теле цикла

- только простейщие операции и типы, а это Byte = 0...255, считанный блок из ОЗУ как массив числе, и сигнатура предварительно переведена в массив чисел

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте аккаунт или войдите в него для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!

Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас

  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу.

×