You are not logged in.
Наконец, я обнаружил способ запускать на выполнение ассемблерный код прямо из main.scm, не используя при этом никаких патчей или чего бы то ни было.
Это похоже на метод CyQ'а при вставке кода в тело main.scm для замены адресов опкодов. Я нашел два опкода, которые могут выполнят ту же функцию в San Andreas.
Это 0572 и 0A3D.
Итак, как это работает.
1. В San Andreas мы имеем 92 чита (кода). Некоторые из них нерабочие, некоторые хорошо известны и часто используются.
2. Указанные опкоды так же хорошо известны. 0572 устанавливает нитро на все такси, 0A3D заставляет проституток платить вам (не имеет значения, я все равно использую 0572).
Но не каждый знает, что эти опкоды работают подобно читам. Они устанавливают один из 92 флагов и игра начинает думать, что вы используете чит (без изменения истории читов, только применяется то, что делает чит).
3. 0A3В это чит #90, 0572 - чит #91
4. Адреса процедур всех читов хранятся в виде простых чисел (в массиве) и могут быть изменены в режиме реального времени через main.scm. Читайте статью "Меняем игровую память через SCM".
5. Суммируя, данный код меняет адрес 91-го чита на адрес внутри main.scm. После этого мы используем этот опкод, игра считывает адрес чита, переходит в тело main.scm на указанное нами место и начинает работать с кодом как ассемблерным.
Используя конструкцию hex..end в Sanny Builder возможно выполнять ЛЮБОЙ код, который вы хотите.
Лично я не очень хорошо знаю ассемблер, поэтому мой пример простой (я добавляю $1000 на счет игрока), но это только начало.
Кто-нибудь, кто хорошо знает ассемблер, может написать процедуру VirtualProtect и тогда нам не потребуется патчить игру с патчем Xieon'а, чтобы изменять некоторые адреса (например, адрес гравитации).
// run asm code 0@ = -429863 &0(0@,1i) = 0xA49960 &0(0@,1i) += @__AsmInjection 0572: 1 &0(0@,1i) = 0 // restore previous value .................. :__AsmInjection hex //Add $1000 to the player money 81 05 50CEB700 E8030000 add [0xB7CE50], 1000 C3 // return end
Этот код добавит 1000 к значению, записанному в 0xB7CE50 (адрес денег игрока). Немного бесполезный пример, но работает!
Обратите внимание: это было протестировано в San Andreas v1.0 US. Если вы имеете v1.01, пожалуйста, протестируйте работает ли код.
Edit: изменен (упрощен) инжект;
А вот и другой пример, посложнее.
Данный мод позволяет активировать любой чит нажатием кнопки Действие (Tab по умолчанию). Все читы активируются последовательно.
http://sannybuilder.com/files/cheater.rar
Last edited by Seemann (10-12-2006 16:07)
Offline
Похоже мы всё больше и больше понимаем , что R* постарались сделать возможности скрипта максимальными .
Offline
Хе, если не считать того, что для обнаружения этих "максимальных возможностей" требуется хорошенько покопаться в экзешнике. Скорее, это простые дырки, уязвимости движка.
Offline
2Seemann
Данный мод позволяет активировать любой чит нажатием кнопки Действие (Tab по умолчанию). Все читы активируются последовательно.
http://sannybuilder.com/files/cheater.rar
А зчем в коде последней строкой:
00C3: read_mem_address
, если патч не нужен?
2Alexander
R* постарались сделать возможности скрипта максимальными
Они об этом даже не знают, т.к. в стандартном мейне такое не применяется, это практически "описание инструкций новых функций" через мейн. Создатели делали бы это через exe.
Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ
Offline
2Capushon
debug_mode работает
на самом деле это не имеет отношения к опкоду 00C3. Это концовка кода на ассемблере, а точнее инструкция С3 - return. Можешь посмотреть в примере в первом посте.
Исходный код такой:
03C4: set_status_text_to $4 0 'FEC_NMN' $4 = -1 while true wait 250 if 00E1: key_pressed 0 4 then inc($4) 0@ = -429863 &0(0@,1i) = 10789350 0572: 1 03E5: 'CHEAT1' wait 1000 end end end_thread hex A1 7099A4 00 // mov eax, $4 50 // push eax E8 7FE19EFF // call 0x438370 = 4424560 83 C4 04 // add esp, 4 C3 // return end
правда не пытайтесь вставить это в другой майн, там все оффсеты посчитаны вручную. Если добавить хоть один опкод, работать не будет. Буду думать, правда асм плохо знаю.
Кстати говоря, теперь можно переделать процедуру @WriteMem, потому как через асм можно записывать и 1, и 2 байта одной командой, а не мучиться с установкой битов.
Last edited by Seemann (10-12-2006 09:32)
Offline
2Seemann
теперь можно переделать процедуру @WriteMem, потому как через асм можно записывать и 1, и 2 байта одной командой, а не мучиться с установкой битов.
Да, хорошо-бы! И не с безусловным, а "плавающим" переходом на ассемблерный инжект.
Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ
Offline
И не с безусловным, а "плавающим" переходом на ассемблерный инжект.
С этим-то проблем нет. В примере в первом посте как раз и используется "плавающий" переход
&0(0@,1i) = 0xA49960 &0(0@,1i) += @__AsmInjection
это мы высчитываем глобальную позицию метки @__AsmInjection с учетом адреса main.scm. Т.е. фактически можно инжект передвинуть в любое место майна.
Проблема заключается в другом.
E8 7FE19EFF // call 0x438370 = 4424560
это я вызываю процедуру из gta-sa.exe по адресу 0x438370.
E8 - опкод инструкции call, если параметр идет как локальное смещение. 0xFF9EE17F это локальное смещение от данной команды до процедуры.
А есть еще call с параметром как глобальный адрес. Т.е. там значение не зависит уже от позиции команды, оно постоянно: 0x438370. Но у меня не получается заставить это работать.
Кстати, для тех кто в танке:
Описание всех инструкций ассемблера
Offline
2Seemann
вызываю процедуру из gta-sa.exe по адресу 0x438370
Что это за процедура?
А есть еще call с параметром как глобальный адрес.
Это бы наверное лучше.
В крайнем случае спросить у Стива, CyQ'а по-поводу локального смещения от данной команды до процедуры, или отдельно написать калькулятор высчитывающий смещение, а потом hiew'ом это дело править (ну это конечно совсем через зад) :-)
Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ
Offline
2Seemann
Ещё одна сумасшедшая идея - взять свободный OPR-код и расписать его нужными знаками подстановки для hex'а, а локальное смещение задать переменной.
Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ
Offline
Что это за процедура?
Процедура запуска чита, та самая, которая используется и в опкоде 0572 и 0A3D. Параметр один: ID чита (0..91)
В крайнем случае спросить у Стива, CyQ'а
CyQ уже почти год не появлялся на гтафорумс, так что от него помощи мы не дождемся (да и если он был бы с нами, кодинг бы развивался в другом направлении, я думаю).
Локальное значение можно посчитать самому, я сам так делал. Высчитываешь глобальный адрес опкода call (через hex смотришь адрес команды после call в майн.скм + A49960) и отнимаешь адрес процедуры.
взять свободный OPR-код и расписать его нужными знаками подстановки для hex'а, а локальное смещение задать переменной.
Не совсем понял, что ты имеешь в виду.
В любом случае, должен быть достаточно простой способ вставки ассем. кода в любое место майна и активация его.
Offline
Блин, на версии 1.01, cheater.rar не работает ... :-(
Почему себе не поставишь SA 1.01 ?Кстати зачем ты дополнительно выводишь бокс 'CHEAT1' , он же и так показывается при срабатывании чита?
Я пробовал ставить патч, но что-то не получилось, видимо пиратка кривая. Да и нет особой необходимости в этом, большинство, я думаю, все равно на 1.0 сидят + 1.01 официально нельзя модифировать.
С боксом не все так просто. На самом деле в экзешнике 2 процедуры активации чита. Первая это чисто сама активация одной из 91 процедуры, которые создают машины, дают оружие, и т.д. Вторая - это процедура, которая срабатывает при вводе чита вручную. Она не только вызывает первую процедуру, но еще и меняет статистику, выводит сообщение и т.д. А т.к. я активирую первую процедуру, то естественно там никакого сообщения не будет.
Я, кстати, нашел способ вызвать процедуру независимо от положения в исходнике, так что теперь мод можно добавлять хоть куда.
Еще нашел в экзешнике 1.01 адреса main.scm и этой процедуры, так что можно сконвертировать код под версию 1.01
EDIT: запостил мод здесь. Дальнейшее обсуждение конкретно этого мода ведем в указанной теме.
Last edited by Seemann (13-12-2006 16:53)
Offline
Проблема заключается в другом.
E8 7FE19EFF // call 0x438370 = 4424560это я вызываю процедуру из gta-sa.exe по адресу 0x438370.
E8 - опкод инструкции call, если параметр идет как локальное смещение. 0xFF9EE17F это локальное смещение от данной команды до процедуры.
А есть еще call с параметром как глобальный адрес. Т.е. там значение не зависит уже от позиции команды, оно постоянно: 0x438370. Но у меня не получается заставить это работать.
А GetProcAddress пробовал? Сам проверить не могу игры пока нет
Offline
2Sanchez:
The GetProcAddress function returns the address of the specified exported dynamic-link library (DLL) function.
Эта процедура используется только для поиска процедур в дллках, т.е. когда основное приложение вызывает что-то из этой библиотеки.
Применительно к вызову процедур из скм это вряд ли может подойти. Да, и я нашел как можно вызвать процедуру: записать в переменную ее адрес, а потом сделать call dword ptr (т.е. вызов с передачей указателя на 32-битное значение в памяти).
Offline
Немного инфы о вызове процедур и указателях.
Команда call - это аналог опкода 0050: gosub. Движок игры переходит на указанный адрес, а после выполнения возвращается обратно командой return.
Адрес можно передавать 2-мя способами
1. напрямую (immediate value). Например: call 0x438370 не могу понять как сделать
2. через переменную (адрес памяти) или регистр. Например call eax; call [eax]
Для каждого способа есть свой опкод, определяющий не только сму команду, но и тип параметра, его размер. Т.е. также как и в скм.
Разница между call eax и call [eax] такова:
в первом случае мы передаем само значение в регистре, т.е. игра будет читать, что записано в регистре и вызывать процедуру по данному адресу.
Во втором случае, значение регистра - это указатель на ячейку памяти, в которой содержится значение, т.е. игра будет читать этот адрес и вызывать процедуру по адресу, который там записан.
Указатели обозначаются скобками [].
Перед указателем [] ставится размер области памяти, которое нужно читать:
call dword ptr [eax] - прочитать 4 байта по адресу в eax и вызвать процедуру по этому значению call word ptr [eax] - прочитать 2 байта по адресу в eax и вызвать процедуру по этому значению call byte ptr [eax] - прочитать 1 байт по адресу в eax и вызвать процедуру по этому значению
Естественно, указатели могут использоваться по всех других командах, например
mov eax, dword ptr [ecx+1] - в eax записываются 4 байта памяти по адресу, записанному в ecx +1.
Например, если в ecx записано 10000, то игра прочитает 4 байта, начиная с 10001-го байта.
Если кто-то обладает знаниями ассемблера и может объснить отдельные элементы простым языком - пишите в этой теме.
Last edited by Seemann (14-12-2006 14:53)
Offline
Если кто-то обладает знаниями ассемблера и может объснить отдельные элементы простым языком - пишите в этой теме.
Вот отличная книга там достаточно просто все описанно.
Команда: CALL операнд
Назначение: Вызов процедуры
Процессор: 8086Сохраняет текущий адрес в стеке и передает управление по адресу, указанному в операнде. Операндом может быть непосредственное значение адреса (метка в ассемблерных программах), регистр или переменная, содержащие адрес перехода. Если в качестве адреса перехода указано только смещение, считается, что адрес расположен в том же сегменте, что и команда CALL. При этом, так же как и в случае с JMP, выполняется ближний вызов процедуры. Процессор помещает значение регистра EIP (IP при 16-битной адресации), соответствующее следующей за CALL команде, в стек и загружает в EIP новое значение, осуществляя тем самым передачу управления. Если операнд CALL — регистр или переменная, то его значение рассматривается как абсолютное смещение, если операнд — метка в программе, то ассемблер указывает ее относительное смещение. Чтобы осуществить дальний CALL в реальном режиме, режиме V86 или в защищенном режиме при переходе в сегмент с теми же привилегиями, процессор помещает в стек значения регистров CS и EIP (IP при 16-битной адресации) и выполняет дальний переход аналогично команде JMP.
Last edited by Sanchez (16-12-2006 09:02)
Offline
Вот отличная книга там достаточно просто все описанно.
А еще есть что-нибудь? Она у тебя в электронном варианте?
Вообще лучше всего написано в руководстве от Интела, правда примеров маловато.
Offline
Если кому надо могу написать статейку об основных командах ассемблера с примерами. Если не надо, то не напишу.
Offline
Надо! Пиши.
Offline
2Seemann:
Я имел ввиду для тех, кто вообще в этом не рубит. Для тебя это не интересно будет. Конечно можно и подробно расписать, но тогда другим будет не понятно.
Вот думаю о чем бы написать, план таков:
1. регистры (eax,ebx и т.д.)
2. стек (push\pop)
4. осн. команды (mov,jmp)
5. арифметические (add,sub,div,mul)
!!! логические (or,xor,not ) - думаю пока не надо !!!
6. условные переходы (cmp, je,jne,jb,jg,jl,ja)
7. вызов функций (call,ret)
8. Др.команды - пока непридумал.
Offline
Лучше всего написать самое основное. Если писать простыни никто читать их не будет, главное объяснить суть (принцип работы, передача параметров, основы синтаксиса - указатели, регистры, флоат-регистры). Можно подыскать линки, думаю эта тема освещена более чем достаточно в инете.
Offline
Думаю никому это не надо
Завтра выложу что успел написать.
Last edited by Sanchez (10-01-2007 10:07)
Offline
2Seemann
вызываю процедуру из gta-sa.exe по адресу 0x438370
Что это за процедура?
У меня она называется EnableCheatLegimate - выставить флаг чита, без установки статуса читера.
; выставить флаг чита "легально" (без установки статуса читера) .text:00438370 .text:00438370 gta_enable_cheat_legimate proc near ; CODE XREF: _opcode_handler_26+510p .text:00438370 ; _opcode_handler_13+E48p .text:00438370 .text:00438370 arg_0 = dword ptr 4 .text:00438370 .text:00438370 000 mov eax, [esp+arg_0] .text:00438374 000 mov ecx, ds:gta_cheat_handlers[eax*4] .text:0043837B 000 test ecx, ecx .text:0043837D 000 jz short loc_438381 .text:0043837F 000 jmp ecx .text:00438381 ; --------------------------------------------------------------------------- .text:00438381 .text:00438381 loc_438381: ; CODE XREF: gta_enable_cheat_legimate+Dj .text:00438381 000 mov cl, ds:gta_cheats_enabled[eax] .text:00438387 000 test cl, cl .text:00438389 000 setz cl .text:0043838C 000 mov ds:gta_cheats_enabled[eax], cl .text:00438392 000 retn .text:00438392 gta_enable_cheat_legimate endp
Offline
У меня она называется EnableCheatLegimate - выставить флаг чита, без установки статуса читера.
Это известо вопрос вот в чем:
А есть еще call с параметром как глобальный адрес. Т.е. там значение не зависит уже от позиции команды, оно постоянно: 0x438370. Но у меня не получается заставить это работать.
1. напрямую (immediate value). Например: call 0x438370 не могу понять как сделать
Offline
2listener:
а без пересылки в eax нельзя? Просто call глобальный адрес? Если писать оффсет, то работает, я сначала так делал (E8).
В доках вроде написан опкод 9A (call far absolute, address given in operand).
а кажется понял:
far call - a call to a procedure located in the different segment
т.е кол с глобальным адресом работает только при вызове процедуры из другого сегмента (библиотеки, например)?
Offline