<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Как правильно сделать call в своём скрипте?]]></title><description><![CDATA[<p dir="auto">Откопал в игре код:</p>
<pre><code>StartNightImmediately::UsePower - cmp dword ptr [050310B8],01
StartNightImmediately::UsePower+7- jne StartNightImmediately::UsePower+A
StartNightImmediately::UsePower+9- ret 
StartNightImmediately::UsePower+A- xor ecx,ecx
StartNightImmediately::UsePower+C- xor edx,edx
StartNightImmediately::UsePower+E- call Terraria.Main::SkipToTime
StartNightImmediately::UsePower+13- ret 
</code></pre>
<p dir="auto">Есть ещё аналогичные вызовы дня, полдня, вечера... все отличаются только регистрами ECX и EDX перед CALL</p>
<p dir="auto">Есть способ какой-то в свой скрипт добавить вызов этого метода?</p>
<p dir="auto">Пока пробовал только такой вариант (символ debug_flag для одноразового срабатывания):</p>
<pre><code>  cmp byte ptr [debug_flag],0
  je @f
  mov byte ptr [debug_flag],0
  push ecx
  push edx
  xor ecx,ecx
  xor edx,edx
  call Terraria.Main::SkipToTime
  pop edx
  pop ecx
@@:
</code></pre>
<p dir="auto">Но игра вылетает :(</p>
]]></description><link>https://gamehacklab.ru/bb/topic/369/как-правильно-сделать-call-в-своём-скрипте</link><generator>RSS for Node</generator><lastBuildDate>Wed, 10 Jun 2026 06:17:34 GMT</lastBuildDate><atom:link href="https://gamehacklab.ru/bb/topic/369.rss" rel="self" type="application/rss+xml"/><pubDate>Wed, 22 May 2024 08:28:37 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Как правильно сделать call в своём скрипте? on Sat, 25 May 2024 10:19:48 GMT]]></title><description><![CDATA[<p dir="auto">В качестве некого заключения данной темы хочу предложить кусочек своего скрипта, который демонстрирует как передачу параметров в функцию, так и получение от неё результата в случаях, если оные передаются через регистр.</p>
<pre><code>  // начало скрипта (flgRain выведен в таблицу и назначена горячая клавиша на установку значения в 1)
  cmp byte ptr [flgRain],0              // проверяем не было ли команды на смену дождя
  je endRain                            // если нет - завершаем скрипт
  mov byte ptr [flgRain],0              // если была, то сначала сбрасываем флаг обратно (нам не нужно беспрерывно менять дождь туда-сюда, нужно выполнить код лишь единожды)
  pushad                                // сохраняем все регистры в стек
  call Terraria.Main::get_IsItRaining   // проверяем идёт ли сейчас дождь (результат вернётся в регистр EAX)
  test eax,eax                          // 0 - не идёт, 1 - идёт
  je @f                                 // прыжок к секции начала дождя (пропустить остановку дождя) если EAX==0
  call Terraria.Main::StopRain          // останавливаем дождь
  popad                                 // восстанавливаем регистры из стека
  jmp endRain                           // выход из скрипта (не нужно запускать дождь)
@@:
  call Terraria.Main::StartRain         // запустить дождь
  popad                                 // восстановить регистры из стека
endRain:
</code></pre>
<p dir="auto">За идею использования инструкций pushad/popad хочу поблагодарить пользователя "youneuoy" с Discord канала GamehackLab[RU].</p>
]]></description><link>https://gamehacklab.ru/bb/post/874</link><guid isPermaLink="true">https://gamehacklab.ru/bb/post/874</guid><dc:creator><![CDATA[paracetamol]]></dc:creator><pubDate>Sat, 25 May 2024 10:19:48 GMT</pubDate></item><item><title><![CDATA[Reply to Как правильно сделать call в своём скрипте? on Sat, 25 May 2024 10:08:42 GMT]]></title><description><![CDATA[<p dir="auto"><a class="mention plugin-mentions-user plugin-mentions-a" href="https://gamehacklab.ru/bb/uid/1">@StoneWeaver</a> Спасибо за приятные слова!<br />
"попробовал выяснить, какой тип вызовов в этой игре используется" - дело в том, что <strong>я не знал вообще, что типы вызовов бывают разными</strong>. Просто где-то на просторах ютуба наткнулся на ролик обучающий и там рассказчик как раз упомянул, что параметры могут передаваться либо через регистры, либо через стек. Вот эта фраза и тригернула у меня цепочку рассуждений "у меня точно используются регистры при передаче, а что если стек тут вообще не при чём и зря я на нём зациклился" и далее и далее к конечной идее "бэкапим вообще все, регистры меняем только то что нужно, вызываем функцию, восстанавливаем все регистры".</p>
<p dir="auto">Всё верно пишешь - начать нужно было не с экспериментов, а с внимательного изучения кода внутри вызываемой функции и сравнения её с кодом той, которая её вызывает. Подобный анализ даёт понять как передаются параметры в функцию и как вызывающая сторона получает результат (в случае его наличия).</p>
]]></description><link>https://gamehacklab.ru/bb/post/873</link><guid isPermaLink="true">https://gamehacklab.ru/bb/post/873</guid><dc:creator><![CDATA[paracetamol]]></dc:creator><pubDate>Sat, 25 May 2024 10:08:42 GMT</pubDate></item><item><title><![CDATA[Reply to Как правильно сделать call в своём скрипте? on Sat, 25 May 2024 04:55:12 GMT]]></title><description><![CDATA[<p dir="auto"><a class="mention plugin-mentions-user plugin-mentions-a" href="https://gamehacklab.ru/bb/uid/419">@paracetamol</a> Ты прошёл по пути самурая, и пришёл к решению самостоятельно. Это круто! От себя добавлю - если бы ты сразу попробовал выяснить, какой тип вызовов в этой игре используется, возможно, твой путь к правильному решению был бы намного короче :)</p>
]]></description><link>https://gamehacklab.ru/bb/post/871</link><guid isPermaLink="true">https://gamehacklab.ru/bb/post/871</guid><dc:creator><![CDATA[StoneWeaver]]></dc:creator><pubDate>Sat, 25 May 2024 04:55:12 GMT</pubDate></item><item><title><![CDATA[Reply to Как правильно сделать call в своём скрипте? on Thu, 23 May 2024 19:11:05 GMT]]></title><description><![CDATA[<p dir="auto">Я нашёл решение и теперь у меня получилось успешно вызвать функцию - эффект от неё применился и никаких крашей! :blush:</p>
<p dir="auto">Рассказываю и читающему, если ему вдруг тоже интересно</p>
<p dir="auto">Как я и предполагал ранее, функция не читает ничего из стека. <strong>Передача параметров происходит исключительно через регистры.</strong> Для нас это значит следующее: не нужно никакой мороки с изучением и воспроизводством состояния стека. Просто забиваем требуемые параметры в регистры и делаем call.</p>
<p dir="auto"><strong>Причины предыдущих неудач</strong><br />
Игра крашилась у меня не из-за того, что я что-то не так передавал, а из-за того, что вызываемая функция (SkipToTime, см.выше код) почему то:</p>
<ol>
<li>уничтожает значения регистров edi и esi</li>
</ol>
<pre><code>Terraria.Main::SkipToTime+3- push edi
Terraria.Main::SkipToTime+4- push esi
Terraria.Main::SkipToTime+5- sub esp,08
</code></pre>
<ol start="2">
<li>сразу за этим безобразием без бэкапов обнуляет eax</li>
</ol>
<pre><code>Terraria.Main::SkipToTime+8- xor eax,eax
</code></pre>
<p dir="auto">Ну и соответственно после отработки функции и возвращения в исходный код начинали твориться "чудеса" из-за сбоя состояния регистров.</p>
<p dir="auto"><strong>Найденное решение</strong>:</p>
<ol>
<li>бэкап всех регистров общего назначения, а также edi и esi (понятное дело ebp и esp бэкапить не нужно)</li>
</ol>
<pre><code>  push eax
  push ebx
  push ecx
  push edx
  push edi
  push esi
</code></pre>
<ol start="2">
<li>далее заполняем регистры необходимыми значениями (в моём случае это заполненные нулями ecx и edx)</li>
</ol>
<pre><code>  xor ecx,ecx
  xor edx,edx
</code></pre>
<ol start="3">
<li>собственно сам вызов</li>
</ol>
<pre><code>call Terraria.Main::SkipToTime
</code></pre>
<ol start="3">
<li>ну и восстанавливаем состояние регистров (естественно в обратном бэкапу порядке)</li>
</ol>
<pre><code>  pop esi
  pop edi
  pop edx
  pop ecx
  pop ebx
  pop eax
</code></pre>
<p dir="auto"><strong>Всё.</strong></p>
<p dir="auto"><em>В Террарии наступила ночь, часики перемотались на 7:30 вечера, игра не вылетела, я счастлив, мир прекрасен!</em></p>
]]></description><link>https://gamehacklab.ru/bb/post/868</link><guid isPermaLink="true">https://gamehacklab.ru/bb/post/868</guid><dc:creator><![CDATA[paracetamol]]></dc:creator><pubDate>Thu, 23 May 2024 19:11:05 GMT</pubDate></item><item><title><![CDATA[Reply to Как правильно сделать call в своём скрипте? on Thu, 23 May 2024 13:57:07 GMT]]></title><description><![CDATA[<p dir="auto"><a class="mention plugin-mentions-user plugin-mentions-a" href="https://gamehacklab.ru/bb/uid/21">@garik66</a> Я не совсем понимаю.<br />
ret - это возврат из текущей функции к коду, который её вызвал. Место где я делаю call - это не функция. Просто место кода, где я делаю всякие свои штуки.<br />
Намереваюсь вместе с ними при некоторых условиях (взведён debug_flag) сделать так, чтобы отработала функция, находящаяся по адресу после call.<br />
Функция которую я хочу вызвать - SkipToTime</p>
<pre><code>Terraria.Main::SkipToTime - push ebp
Terraria.Main::SkipToTime+1- mov ebp,esp
Terraria.Main::SkipToTime+3- push edi
Terraria.Main::SkipToTime+4- push esi
Terraria.Main::SkipToTime+5- sub esp,08
Terraria.Main::SkipToTime+8- xor eax,eax
Terraria.Main::SkipToTime+A- mov [ebp-0C],eax
Terraria.Main::SkipToTime+D- mov edi,ecx
Terraria.Main::SkipToTime+F- movzx esi,dl
Terraria.Main::SkipToTime+12- movzx eax,byte ptr [058C128D]
Terraria.Main::SkipToTime+19- cmp esi,eax
Terraria.Main::SkipToTime+1B- je Terraria.Main::SkipToTime+4E
Terraria.Main::SkipToTime+1D- call dword ptr [07F45530]
Terraria.Main::SkipToTime+23- mov [ebp-0C],eax
Terraria.Main::SkipToTime+26- cmp byte ptr [058C128D],00
Terraria.Main::SkipToTime+2D- je Terraria.Main::SkipToTime+3A
Terraria.Main::SkipToTime+2F- lea ecx,[ebp-0C]
Terraria.Main::SkipToTime+32- call dword ptr [07F4553C]
Terraria.Main::SkipToTime+38- jmp Terraria.Main::SkipToTime+43
Terraria.Main::SkipToTime+3A- lea ecx,[ebp-0C]
Terraria.Main::SkipToTime+3D- call dword ptr [07F45548]
Terraria.Main::SkipToTime+43- movzx eax,byte ptr [058C128D]
Terraria.Main::SkipToTime+4A- cmp esi,eax
Terraria.Main::SkipToTime+4C- jne Terraria.Main::SkipToTime+1D
Terraria.Main::SkipToTime+4E- mov [ebp-10],edi
Terraria.Main::SkipToTime+51- fild dword ptr [ebp-10]
Terraria.Main::SkipToTime+54- fstp qword ptr [058C0CE8]
Terraria.Main::SkipToTime+5A- cmp dword ptr [058C10B8],02
Terraria.Main::SkipToTime+61- jne Terraria.Main::SkipToTime+82
Terraria.Main::SkipToTime+63- push -01
Terraria.Main::SkipToTime+65- push 00
Terraria.Main::SkipToTime+67- push 00
Terraria.Main::SkipToTime+69- push 00
Terraria.Main::SkipToTime+6B- push 00
Terraria.Main::SkipToTime+6D- push 00
Terraria.Main::SkipToTime+6F- push 00
Terraria.Main::SkipToTime+71- push 00
Terraria.Main::SkipToTime+73- push 00
Terraria.Main::SkipToTime+75- mov ecx,00000007
Terraria.Main::SkipToTime+7A- lea edx,[ecx-08]
Terraria.Main::SkipToTime+7D- call Terraria.NetMessage::TrySendData
Terraria.Main::SkipToTime+82- lea esp,[ebp-08]
Terraria.Main::SkipToTime+85- pop esi
Terraria.Main::SkipToTime+86- pop edi
Terraria.Main::SkipToTime+87- pop ebp
Terraria.Main::SkipToTime+88- ret 
</code></pre>
<p dir="auto">ret в ней есть к слову<br />
Чтобы понять как правильно её вызывать (у неё есть параметры)<br />
<img src="/bb/assets/uploads/files/1716472044213-ff99a16d-351d-4137-9a55-2794fd25a539-image.png" alt="ff99a16d-351d-4137-9a55-2794fd25a539-image.png" class=" img-fluid img-markdown" /><br />
Я проводил искал код её вызывающий и нашёл 4 похожих друг на друга класса<br />
<img src="/bb/assets/uploads/files/1716472155117-2a1397ac-746f-49cf-9280-203d9b24c862-image.png" alt="2a1397ac-746f-49cf-9280-203d9b24c862-image.png" class=" img-fluid img-markdown" /><br />
Каждый из которых отличается в коде только формированием регистров ECX и EDX (гипотеза моя в том, что ECX - первый параметр, а EDX - второй)<br />
Не мудрствуя лукаво решил просто сделать вызов так, как это делает один из этих классов своим методом UsePower:</p>
<pre><code>StartNightImmediately::UsePower - cmp dword ptr [058C10B8],01
StartNightImmediately::UsePower+7- jne StartNightImmediately::UsePower+A
StartNightImmediately::UsePower+9- ret 
StartNightImmediately::UsePower+A- xor ecx,ecx
StartNightImmediately::UsePower+C- xor edx,edx
StartNightImmediately::UsePower+E- call Terraria.Main::SkipToTime
StartNightImmediately::UsePower+13- ret 
StartNightImmediately::UsePower+14- add [eax],al
</code></pre>
<p dir="auto">Т.е. такие 2 xor, затем call</p>
<p dir="auto">Полагаю мой провал связан с тем, что помимо формирования корректного состояния регистров мне ещё нужно было озаботиться тем, чтобы также правильно сформировать стек. Всё дело в стеке? Может кто подсказать как изучить стек в момент перед вызовом call'а и как его повторить в своём коде?</p>
]]></description><link>https://gamehacklab.ru/bb/post/866</link><guid isPermaLink="true">https://gamehacklab.ru/bb/post/866</guid><dc:creator><![CDATA[paracetamol]]></dc:creator><pubDate>Thu, 23 May 2024 13:57:07 GMT</pubDate></item><item><title><![CDATA[Reply to Как правильно сделать call в своём скрипте? on Thu, 23 May 2024 07:33:50 GMT]]></title><description><![CDATA[<p dir="auto"><a class="mention plugin-mentions-user plugin-mentions-a" href="https://gamehacklab.ru/bb/uid/419">@paracetamol</a>  попробуй ret после call добавить - нет возврата из функции, поэтому вылет.</p>
]]></description><link>https://gamehacklab.ru/bb/post/865</link><guid isPermaLink="true">https://gamehacklab.ru/bb/post/865</guid><dc:creator><![CDATA[garik66]]></dc:creator><pubDate>Thu, 23 May 2024 07:33:50 GMT</pubDate></item><item><title><![CDATA[Reply to Как правильно сделать call в своём скрипте? on Wed, 22 May 2024 08:50:02 GMT]]></title><description><![CDATA[<p dir="auto">Вариант с передачей в стек не отличается результатом :(</p>
<pre><code>  cmp byte ptr [debug_flag],0
  je @f
  mov byte ptr [debug_flag],0
  push 00000000
  push 00000000
  call Terraria.Main::SkipToTime
@@:
</code></pre>
]]></description><link>https://gamehacklab.ru/bb/post/864</link><guid isPermaLink="true">https://gamehacklab.ru/bb/post/864</guid><dc:creator><![CDATA[paracetamol]]></dc:creator><pubDate>Wed, 22 May 2024 08:50:02 GMT</pubDate></item></channel></rss>