Kailo
Участник
- Сообщения
- 194
- Реакции
- 896
Как же теперь искать этот offset? К сожалению из-за "благодарности" для Valve за вырезанные названия функций, теперь для написания плагинов приходится познавать основы реверс-инжиниринга.После каждого обновления не забывайте gamedata проверять, если крашит) Сделал плагин с IsValidObserverTarget. Обновили месяц назад и при большом онлайне крашило изредка (спасибо Valve!). Сейчас и вовсе оффсет не найду :(
Если кто знает цЫфры оффсета - может подскажет кто? Мяу
Подготовка. Во-первых найдите и скачайте IDA (такую версию, чтобы был псевдо-декомпилятор встроен, в бесплатной версии его нет).
Мы будем искать функцию по её вызову в какой-нибудь другой функции.
Шаг 1. Открываем исходники слитой версии CSS и пытаемся найти нашу функцию там: VSES/SourceEngine2007
Видим, что функция используется (вызывается) только в классе игрока, так что выбираем src_main/game/server/player.cpp для методов класса CBasePlayer.
В общем-то CS:GO писалась на основе CSS и имеет не мало общих функций и еще больше похожих.
Шаг 2. Выбираем цель для поиска в IDA. Легко будет найти функцию, которая имеет строки в своем коде. Если таких нет, то можно попробовать повторить процесс и найти функцию, вызывающую ту, которая вызывает IsValidObserverTarget.
В этом случае из 6 упоминаний IsValidObserverTarget я выбрал наиболее привлекательное с множеством строк.
bool CBasePlayer::ClientCommand( const CCommand &args )
C-подобный:
else if ( stricmp( cmd, "spec_player" ) == 0 ) // chase next player
{
if ( GetObserverMode() > OBS_MODE_FIXED && args.ArgC() == 2 )
{
int index = atoi( args[1] );
CBasePlayer * target;
if ( index == 0 )
{
target = UTIL_PlayerByName( args[1] );
}
else
{
target = UTIL_PlayerByIndex( index );
}
if ( IsValidObserverTarget( target ) )
{
SetObserverTarget( target );
}
}
return true;
}
Открываем быстрый поиск по окну с помощью Ctrl+F и вводим взятую из искомой функции строку
spec_player
.Двойным нажатием по строке нас перекинет в место нахождения нашей строке в коде бинарного файла.
.rodata:010BF5E2 aSpecPlayer db 'spec_player',0 ; DATA XREF: sub_74A140:loc_74A5DF
Один раз нажимаем ЛКМ на именную метку указанного кода (aSpecPlayer). После чего нажимаем на клавишу X и открываем окно упоминаний нашей переменной.
В данном случае находит лишь одно упоминание, и так же двойным нажатием на найденный код переходим к функции, использующей "spec_player".
Теперь нажимаем TAB и должна открыться новая вкладка с псевдо-кодом нашей функции.
if ( sub_CDEA10(v2, "spec_player") && sub_CDEA10(v2, "spec_player_by_name") )
.К примеру можем видеть на 182 строке условие отдаленно напоминающее условие
if ( GetObserverMode() > OBS_MODE_FIXED && args.ArgC() == 2 )
Только в IDA мы видим это условие инвертированным, т.к. оно отвечает за вызов return.
Функция strtol (string to long) явно нам совпадает с
int index = atoi( args[1] );
(ANSI (char array) to integer)Значит строки 185-196 являются отображением
C-подобный:
if ( index == 0 )
{
target = UTIL_PlayerByName( args[1] );
}
else
{
target = UTIL_PlayerByIndex( index );
}
И вот мы видим на строке 198 условие, которое сопоставляется с нашим вызовом IsValidObserverTarget. И в подтверждение того, мы явно видим вызов виртуальной функции, какой она и должна являться.
Дальше можно опять заметить, что код имеет зеркальное отображение. Логическое условие инвертировано и в блоке if виден return. А значит SetObserverTarget вынесен на 201-ю строку.
Значит мы нашли, что на 198-й строке вызов IsValidObserverTarget. Как получить индекс?
*(_DWORD *)a1 + 1732
Здесь надо быть внимательным и разбираться в арифметике указателей.Но если видите точно такой же вид, но другое число, то можете действовать так же.
1732 это наш оффсет но в байтовом виде, а нам нужен в индексном к массиву указателей.
Просто делим это число на 4 и получим нужный нам индекс.
CBasePlayer::IsValidObserverTarget 433