Я уже говорил тебе, что такое безумие?

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



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


void __thiscall sub_6F629730(void *this)
{
  ++*(_BYTE *)this;
}

signed int __thiscall sub_6F62A5D0(_DWORD *this, int a2, int a3)
{
  sub_6F629730(this);
  ....
}

signed int __thiscall sub_6F62A7B0(int this, int a2, int a3)
{
  int v3; // esi@1
  _DWORD *v4; // ecx@1
  signed int result; // eax@1

  v3 = this;
  v4 = *(_DWORD **)(this + 8);
  result = 0;
  if ( v4 )
  {
    ++*(_DWORD *)(v3 + 4);
    result = sub_6F62A5D0(v4, a2, a3);
    ...
    }
  }
  return result;
}


Краш случился на sub_6F629730, куда пришел this равный нулю. А если глянуть на код, то можно проследить цепочку:
  • sub_6F62A7B0 проверяет, равен ли v4 нулю — если так, то вызова не будет;
  • затем идет вызов sub_6F62A5D0, куда отсылается v4
  • затем оно же передается в sub_6F629730
  • и уже тут оно оказалось нулём.
Что за херня?

Я проверил ASM-код, в ходе выполнения никто аргумент не модифицирует. Ноль на самом деле каким-то образом прокрался в вызов, причем незаметно. Единственно возможное объяснение — в строке
++*(_DWORD *)(v3 + 4);

получается ссылка на тот же адрес, что и
*(_DWORD **)(this + 8);


И после увеличения числа на 1 перед вызовом оно становится нулём. Т.е. в счетчике каким-то образом оказалось 0xFFFFFFFF. Количество возгласов WTF у меня от этого только увеличивается.

В редких случаях функция падает не с нулём, а с неким маленьким числом, достаточным, чтобы вывалиться за пределы памяти процесса. Легче от того, что проверка хотя бы верна, не становится совсем

=\

5 комментариев

avatar
блог по доте…
avatar
Написать блог — это тоже способ охладить траханье
avatar
Не, Лич, тут нужно логгировать значение v4 перед вызовом sub_6F62A5D0 и sub_6F629730. Из того, что ты привёл, оно может только из вне меняться.

++*(_DWORD *)(v3 + 4);
не может менять v4. Потому что тут меняется *(this + 4), v4 — это *(this + 8), и они не перекрываются, если _DWORD — это 4 байта.
  • tmn
  • 0
avatar
Я с указателями не дружу, подумал, может, там ссылка на this+8 оказалась
Воздействий извне мне неизвестно, в том месте никаких джампов рядом нет, а выполнение линейное ведь
avatar
Так а что за структура по адресу this? Может её ОС или варик из другого потока меняет? Или хук какой-нибудь выполняется по пути, которого в этих исходниках нет.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.