#1 09-12-2006 04:36

Seemann
Registered: 07-08-2006
Posts: 2,156

[SA] Выполняем ассемблерный код из main.scm

Перевод с английского

Наконец, я обнаружил способ запускать на выполнение ассемблерный код прямо из 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

#2 09-12-2006 13:15

Alexander
Registered: 19-08-2006
Posts: 184
Website

Re: [SA] Выполняем ассемблерный код из main.scm

Похоже мы всё больше и больше понимаем , что R* постарались сделать возможности скрипта максимальными .

Offline

#3 09-12-2006 14:35

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

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

Offline

#4 10-12-2006 09:02

Capushon
Registered: 13-08-2006
Posts: 352
Website

Re: [SA] Выполняем ассемблерный код из main.scm

2Seemann

Данный мод позволяет активировать любой чит нажатием кнопки Действие (Tab по умолчанию). Все читы активируются последовательно.
http://sannybuilder.com/files/cheater.rar

А зчем в коде последней строкой:

00C3: read_mem_address

, если патч не нужен?

2Alexander

R* постарались сделать возможности скрипта максимальными

Они об этом даже не знают, т.к. в стандартном мейне такое не применяется, это практически "описание инструкций новых функций" через мейн. Создатели делали бы это через exe.


Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ

Offline

#5 10-12-2006 09:11

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

2Capushon
debug_mode работает wink

на самом деле это не имеет отношения к опкоду 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

#6 10-12-2006 14:57

Capushon
Registered: 13-08-2006
Posts: 352
Website

Re: [SA] Выполняем ассемблерный код из main.scm

2Seemann

теперь можно переделать процедуру @WriteMem, потому как через асм можно записывать и 1, и 2 байта одной командой, а не мучиться с установкой битов.

Да, хорошо-бы! И не с безусловным, а "плавающим" переходом на ассемблерный инжект.


Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ

Offline

#7 10-12-2006 15:23

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

Capushon wrote:

И не с безусловным, а "плавающим" переходом на ассемблерный инжект.

С этим-то проблем нет. В примере в первом посте как раз и используется "плавающий" переход

&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

#8 10-12-2006 18:14

Capushon
Registered: 13-08-2006
Posts: 352
Website

Re: [SA] Выполняем ассемблерный код из main.scm

2Seemann

вызываю процедуру из gta-sa.exe по адресу 0x438370

Что это за процедура?

А есть еще call с параметром как глобальный адрес.

Это бы наверное лучше.

В крайнем случае спросить у Стива, CyQ'а по-поводу локального смещения от данной команды до процедуры, или отдельно написать калькулятор высчитывающий смещение, а потом hiew'ом это дело править (ну это конечно совсем через зад)  :-)


Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ

Offline

#9 10-12-2006 18:21

Capushon
Registered: 13-08-2006
Posts: 352
Website

Re: [SA] Выполняем ассемблерный код из main.scm

2Seemann
Ещё одна сумасшедшая идея - взять свободный OPR-код и расписать его нужными знаками подстановки для hex'а, а локальное смещение задать переменной.


Сначала ты надежда и гордость,
Потом о спину ломают аршин. (c)БГ

Offline

#10 11-12-2006 09:53

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

Capushon wrote:

Что это за процедура?

Процедура запуска чита, та самая, которая используется и в опкоде 0572 и 0A3D. Параметр один: ID чита (0..91)

В крайнем случае спросить у Стива, CyQ'а

CyQ уже почти год не появлялся на гтафорумс, так что от него помощи мы не дождемся (да и если он был бы с нами, кодинг бы развивался в другом направлении, я думаю).
Локальное значение можно посчитать самому, я сам так делал. Высчитываешь глобальный адрес опкода call (через hex смотришь адрес команды после call в майн.скм + A49960) и отнимаешь адрес процедуры.

взять свободный OPR-код и расписать его нужными знаками подстановки для hex'а, а локальное смещение задать переменной.

Не совсем понял, что ты имеешь в виду.

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

Offline

#11 13-12-2006 16:41

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

Capushon wrote:

Блин, на версии 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

#12 14-12-2006 10:26

Sanchez
Registered: 18-08-2006
Posts: 280

Re: [SA] Выполняем ассемблерный код из main.scm

Seemann wrote:

Проблема заключается в другом.

E8 7FE19EFF     // call 0x438370 = 4424560

это я вызываю процедуру из gta-sa.exe по адресу 0x438370.
E8 - опкод инструкции call, если параметр идет как локальное смещение. 0xFF9EE17F это локальное смещение от данной команды до процедуры.
А есть еще call с параметром как глобальный адрес. Т.е. там значение не зависит уже от позиции команды, оно постоянно: 0x438370. Но у меня не получается заставить это работать.

А GetProcAddress пробовал? Сам проверить не могу игры пока нет sad

Offline

#13 14-12-2006 11:45

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

2Sanchez:

The GetProcAddress function returns the address of the specified exported dynamic-link library (DLL) function.

Эта процедура используется только для поиска процедур в дллках, т.е. когда основное приложение вызывает что-то из этой библиотеки.
Применительно к вызову процедур из скм это вряд ли может подойти. Да, и я нашел как можно вызвать процедуру: записать в переменную ее адрес, а потом сделать call dword ptr (т.е. вызов с передачей указателя на 32-битное значение в памяти).

Offline

#14 14-12-2006 12:57

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

Немного инфы о вызове процедур и указателях.

Команда 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

#15 15-12-2006 09:33

Sanchez
Registered: 18-08-2006
Posts: 280

Re: [SA] Выполняем ассемблерный код из main.scm

Если кто-то обладает знаниями ассемблера и может объснить отдельные элементы простым языком - пишите в этой теме.

Вот отличная книга там достаточно просто все описанно.

Команда: 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

#16 15-12-2006 10:59

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

Sanchez wrote:

Вот отличная книга там достаточно просто все описанно.

А еще есть что-нибудь? Она у тебя в электронном варианте?

Вообще лучше всего написано в руководстве от Интела, правда примеров маловато.

Offline

#17 09-01-2007 09:34

Sanchez
Registered: 18-08-2006
Posts: 280

Re: [SA] Выполняем ассемблерный код из main.scm

Если кому надо могу написать статейку об основных командах ассемблера с примерами. Если не надо, то не напишу.

Offline

#18 09-01-2007 09:55

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

Надо! smile Пиши.

Offline

#19 09-01-2007 13:17

Sanchez
Registered: 18-08-2006
Posts: 280

Re: [SA] Выполняем ассемблерный код из main.scm

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

#20 09-01-2007 14:15

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

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

Offline

#21 10-01-2007 10:04

Sanchez
Registered: 18-08-2006
Posts: 280

Re: [SA] Выполняем ассемблерный код из main.scm

Думаю никому это не надо sad

Завтра выложу что успел написать.

Last edited by Sanchez (10-01-2007 10:07)

Offline

#22 10-01-2007 15:28

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: [SA] Выполняем ассемблерный код из main.scm

Capushon wrote:

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

#23 11-01-2007 10:29

Sanchez
Registered: 18-08-2006
Posts: 280

Re: [SA] Выполняем ассемблерный код из main.scm

listener wrote:

У меня она называется EnableCheatLegimate - выставить флаг чита, без установки статуса читера.

Это известо smile вопрос вот в чем:

А есть еще call с параметром как глобальный адрес. Т.е. там значение не зависит уже от позиции команды, оно постоянно: 0x438370. Но у меня не получается заставить это работать.

1. напрямую (immediate value). Например: call 0x438370 не могу понять как сделать

Offline

#24 11-01-2007 22:24

listener
From: Vice City
Registered: 09-11-2006
Posts: 616
Website

Re: [SA] Выполняем ассемблерный код из main.scm

2Sanchez:
mov eax, 438370h ; B7 70 83 04 00
call eax ; FF D0

Offline

#25 12-01-2007 06:03

Seemann
Registered: 07-08-2006
Posts: 2,156

Re: [SA] Выполняем ассемблерный код из main.scm

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

Board footer

Powered by FluxBB