Перейти к содержанию

Туторы по CE Autoassembler Engine


MasterGH

Рекомендуемые сообщения

Здесь будет рассматриватся и может обсуждаться/дополняться моё руководство по Autoassembler Engine.

Нужные ссылки на CE:

1. Сайт английской версии (последняя версия CE 6.0 на 20 апреля 2011 )

2. Русская CE 5.6 (устанавливается поверх английской CE 5.6 находящаяся на официальном сайте; если хотите генерировать трейнеры, то только лучше на этой версии пока не вышла версия CE6.1)

3. Русская CE 5.5

Статья в которой обсуждается работа с автоассемблером (весь пункт 3):

DevilMyCry.rar.

Эту статью лучше прочитать после чтения информации ниже.

Дополнительная информация:

Если делаете читы для себя, то Вам будет достаточно автоассемблерных скриптов CE. Если нужны трейнеры, то их генерировать может CE 5.6 и будущая CE 6.1. CE 6.0 генерировать трейнеры не умеет, но зато поддерживает LUA - скрипты, которые могут создавать трейнеры скриптами только при наличии CE6.0. Чтобы делать трейнеры на LUA скриптах нужно иметь опыт программирования. Для новичков проще пользоваться автоассемблерными скриптами.

На официальном сайте ожидается конечный реализ CE 6.1 с поддержкой русского языка.

Зайдите в подфорум реализы Cheat Engine чтобы попробовать возможности CE 6.1 Альфа 8.

-----------------------------------------

1. Обзор автоассемблера

Посмотрим с чем придётся иметь дело...

post-3-1303268956,32_thumb.png

Рис.1 Окно автоассемблера после генерации шаблона

Если Вы решите исправить код игры, то вам придётся писать код в этом окне. Также Вам вручную придётся убирать комментарии если они вам мешают. К сожалению разработчик Дарк Байт не позаботился о том как убрать эти комментарии одним махом.

Сейчас я напишу как сгенерировать такой шаблон. А затем как и что в нём редактировать.

1) Подключитесь к процессу игры.

Надеюсь Вы знаете как это делать. В версии CE 6.0 это можно сделать через значок "Компьютер"

2) Найдите адрес нужного параметра1 в игре

3) На адресе вызовете меню правым кликом мыши и поставьте брейкпоинт "на запись" или "на доступ". Надеюсь вы знаете как это сделать, если немного знаете английский.

4) Войдите в игру и измените значение параметра1

5) Если вы сделали всё правильно, то в окне брейкпоинтов появится инструкция или их будет несколько.

6) Перейдите по инструкции в дизассемблер. Надеюсь вы знаете как это сделать, если немного знаете английский.

Ну а теперь смотрите рисунок. Он сделан на основе статьи, которую я выложил выше:

post-3-1303270075,17_thumb.png

Рис.2 Создание скрипта инъекции кода

Итак вы прошли весь путь создания скрипта. Вы не только узнали как генерировать шаблон, но и узнали куда вписывать новый код.

С помощью скриптов вы можете:

1) встроить чит-код удобно вклинив новое условие в код игры;

2) быстро проверить работоспособность чит-кода;

3) "получить" байты чит-кода для создания трейнера.

Скрипт открывает перед вами МОЩНЫЕ возможности. Иногда нужно извернуться, чтобы написать скрипт. В этом есть кайф - изменить код игры под себя, обмануть игру.

Это было знакомство, а теперь переходим к деталям.

2 Скриптовые инструкций

Скрипты включают в себя инструкции ассемблера (будут разобраны позже), а также ряд специальных скриптовых команд.

Существуют две основные директивы


[DISABLE] // восстановить оригинальный код
[ENABLE] // включить новое условие

Листинг 1

Под каждой директивой располагается код активации и деактивации чита.

Пример


0081e159:
db 90 90

[DISABLE]
0081e159:
dec [ecx] // вычесть единицу из адреса ecx (ecx считайте «переменной»)
[ENABLE]

Листинг 2

Этот приём позволяет очень просто внедрить чит-код. Вычитание никогда не произойдёт. Подробнее будет ниже.

Бывают такие случае что в ecx, могут проскакивать разные адреса и поэтому требуется сделать сложное внедрение. Для того чтобы это сделать нужно, вклинить условие в место 0081e159: db 90 90 изменив и не нарушив логику кода. Сделать это можно вписав прыжок в адрес 0081e159, который затрёт часть других инструкции (располагающихся ниже) ноп-ами. Об этом внедрении будет позже. А сейчас вернёмся к простому затиранию инструкций нопами.

На этапе внедрения чит-кода вы можете увидеть, что каждая ассемблерная инструкция занимает определённое количество байт кода. Будьте внимательны и соблюдайте размер и логику, чтобы не напортачить чего либо, а то будет вылет из игры. Наверно, вы сталкивались – запускаешь трейнер чей-то и тут ВЫЛЕТ. Вот чтобы этого не было надо быть внимательным и знать ассемблерные инструкции.

Возьмём за пример.


Code :0081e159 - ff 09 - dec [ecx] //(это можно посмотреть в окнах бряков или окне дизассемблера)

Листинг 3

Как видно тут два байта занимает инструкция dec [ecx]. Думаю вы знаете что она означает вычитание единицы из адреса в ecx. Допустим можно стереть эту инструкцию, чтобы, например, патроны не вычитались.

Чтобы инструкцию «потереть» нужно забить её «ноп»-ами. И сделать это можно либо так


0081e159:
nop
nop

[DISABLE]
0081e159:
dec [ecx]
[ENABLE]

Листинг 4

Либо так


0081e159:
db 90 90

[DISABLE]
0081e159:
dec [ecx]
[ENABLE]

Листинг 5

Либо так


0081e159:
db 90 90

[DISABLE]
0081e159:
db ff 09 // тоже самое что dec [ecx]
[ENABLE]

Листинг 6

db означает данные байта (data byte). Таким образом в данном случае патроны не будут изменяться.

Но что делать, если я хочу чтобы патронов было жёстко 100 штук. Для этого нужно вписать


Mov [адрес или регистр], патроны. 

Листинг 7

Я сейчас точно не помню, но эта инструкция занимает, вроде, пять байт. А у нас доступно только два свободных байта (см. листинг 3) и как же быть?! Скрипт ниже, естественно, работать не будет


0081e159:
Mov [ecx],#100 // крах игры
//затираются нижестоящие инструкции с нарушением логики кода

[DISABLE]
0081e159:
dec [ecx]
[ENABLE]

Листинг 8

..ведь мы затрём пять байтов вместо двух. Игра вылетит. Для того чтобы игра не вылетела, нужно быть внимательным и соблюдать логику кода. Это это всё очень просто.

Смотрим нижестоящие инструкции, например, одна из них будет такой.

Code :0081e159 - ff 09 - dec [ecx]

Code :0081e15b - xx xx xx xx xx– mov eax,[ecx]

Листинг 9

(код байтов инструкции mov я точно не помню, ссори, смотреть лень)

Прыжок на свободное место в котором мы укажем новое условие занимает пять байт это "eb xx xx xx xx" . Это значит, что прыжок затрёт пять байт, начиная с адреса 0081e159 и оставит два байта «ошмётка» последующей инструкции (ий) которые выделены красным. Ошмётки мы затираем ноп-ми (иначе будет вылет) и восстанавливаем инструкции в выделенной памяти соблюдая логику кода.

Совет.

Вам нужно обращать внимание, что когда вы внедряете чит-код, то вы затераете пять байт по стандарту прыжком

Jmp адрес (занимает пять байт)

или в редких случаях

call адрес (занимает пять байт)

Таким образом, скрипт примет вид ниже. Появляются новые скриптовые команды.


Alloc(newmem,2024) //выделение памяти рамзмером 2024 байт, которые округляться до 4 кб
Label(x1) //метка адреса

newmem:
Mov [ecx],#100
mov eax,[ecx] //дописали стёртую инструкцию
jmp x1

0081e159:
Jmp newmem
x1:
nop //наши 2 ошмётка
nop

[DISABLE]
0081e159:
dec [ecx]
mov eax,[ecx]
dealloc(newmem)//высвобождаем выделённую память,чтобы не засорять память.
[ENABLE]

Листинг 10

Теперь игра не должна вылетать.

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


mov ecx,[eax]
mov edx,[esp+04]//<< здесь сработал бряк
...
core.dll+4285C: //<<адрес кода игры

Листинг 11

Инструкция mov edx,[esp+04] работает с адресом здоровья как моего игрока, так и других игроков. Что бы прописать здоровье моего игрока я нашёл многоуровневый указатель (как это делать напишу потом) и построил скрипт с фильтром. Сам фильтр можно видеть ниже.


mov ebx,[core.dll+00155744] //строим многоуровневый указатель
mov ebx,[ebx+350]
add ebx,43C //ebx=[[core.dll+00155744h]+350h]+43Ch – многоуровневый указатель,
cmp eax,ebx //если игрок наш, то прописать 250 очков здоровья
pop ebx //восстановили ebx
jne short originalcode
mov byte ptr [eax],#250 //пишем здоровье нашему гироку
originalcode: //метка оригинального кода
mov ecx,[eax] //дописываем затёртые инструкции для восстановления логики кода
mov edx,[esp+04]
push ebx  //регистр нам будет нужен, поэтому запихнём его в стек и потом вернём обратно

Листинг 12

А теперь листинг 12 встроим весь скрипт.


UnrealTournament2003+ (InfHealth)*/

[ENABLE]
alloc(newmem,2024)
label(returnhere)
label(originalcode)

newmem:

push ebx
mov ebx,[core.dll+00155744]
add ebx,350
mov ebx,[ebx]
add ebx,43C
cmp eax,ebx //ebx=[[core.dll+00155744h]+350h]+43Ch
pop ebx

jne short originalcode
mov byte ptr [eax],#250

originalcode:
mov ecx,[eax]
mov edx,[esp+04]
jmp returnhere

core.dll+4285c:
jmp newmem
nop
returnhere:

[DISABLE]
core.dll+4285c:
mov ecx,[eax]
mov edx,[esp+04]

/*MasterGH(c) 04.01.08. 

Листинг 13

Обратите внимание на то, как мы встроили новое условие. Мы сравнили игрока со своим по его указателю и если это свой игрок, то запишем ему полное здоровье.

Совет.

Внимательно следите нужно ли сохранения регистра флагов pushf/popf. В большинстве случаев это не нужно, в противном будет измнена логика и может быть крах игры.

В скриптах можно много чего «мутить». Разберём специальные команды скрипта (возможно это не все команды, см. справку CE)

ALLOC(имя, размер)- выделение памяти

DEALLOC(имя) - высвобождение памяти

LABEL(имя) - объявление меток

FULLACCESS(адрес/метка, размер) - установка полного доступа по адресу

REGISTERSYMBOL(имя) - регистрация метки, метка будет доступна в окне адресов и вдругих скриптах

UNREGISTERSYMBOL(имя) - убираем метку

DEFINE(имя,инструкция) - почти неприменятся, если инструкция повторяется то удобно её обзвать и присвоить имя

INCLUDE(имя файла) - учитывает метки других файлов-скриптов

LOADBINARY(адрес,имя файла) - загрузка данных или кода из файла по данному адресу

CREATETHREAD(адрес) - создание потока, который будет выполняться начиная с адреса

LOADLIBRARY(имя файла) - подгрузка библиотеки

READMEM(адрес,размер) - в скрипт вставляются байты с некоторого адреса.

db, dw, dd - означает вставка байтов, 2 байтов, 4 байтов.

Ну и примеры из англоязычной справки

Базовая основа скрипта.


jmp 00410000
nop
nop
nop

00410000:
mov [00580120],esi
mov [esi+80],ebx
xor eax,eax
jmp 00451031
00451029:

Листинг 14

Использование меток.



00451029:
jmp 00410000
nop
nop
nop
mylabel:

00410000:
mov [00580120],esi
mov [esi+80],ebx
xor eax,eax
jmp mylabel
label(mylabel)

Листинг 15

Использование выделения памяти



00451029:
jmp 00410000
nop
nop
nop

00410000:
mov [alloc1],esi
mov [esi+80],ebx
xor eax,eax
jmp 00451031
alloc(memloc1,4)

Листинг 16

Использование меток и выделения памяти


label(mylabel)

00451029:
jmp 00410000
nop
nop
nop
mylabel:

00410000:
mov [alloc1],esi
mov [esi+80],ebx
xor eax,eax
jmp mylabel
alloc(alloc1,4)

Листинг 17

Установка полного доступа.

Обычно, используется совместно с областью неиспользуемого кода. Мной не рекомендуется, разве что в очень специфических задачах. Стоит отказаться от codecave (дыр кода), чтобы это не приводило к краху игры, а пользоваться выделением памяти.


//из-за выравнивания кратному 1 странице памяти…

00451029:
jmp 00410000
nop
nop
nop

00410000:
mov [00400800],esi
mov [esi+80],ebx
xor eax,eax
jmp 00451031
FULLACCESS(00400800,4) //доступ будет не к 4-м байтам, а к 4 кб (в 32 разрядных системах и 8 кб в 64 рязрядных)

Листинг 18

Использование DEFINE, как переопределение инструкций.


00400500:
clear_eax
DEFINE(clear_eax,xor eax,eax)

Листинг 19

Использование чтения памяти некоторого размера


alloc(x,16)
alloc(script,2048)

script:
mov eax,[x]
mov edx,[x+c]
ret

x: // по этой метке будет записано 16 байт с адреса 00410000
readmem(00410000,16)

Листинг 20

Пару слов стоит сказать о проверочных байтах. Все они вместе являются уникальной последовательностью (так предполагается) по которой можно установить адрес внедрения. Это нужно чтобы чит-код работал со всеми версиями игры.

Пару слов про шаблоны.

Шаблоны, возможно требуется доработать, поэтому о них пока писать руководство не буду.

Опции Перехват API и переопределения кода, довольно специфичны и пока рассматриваться не будут.

В общем если хотите научится писать скрипты, то учите ассемблерные инструкции и читайте темы на этом форуме.

Если вам нужно в скрипте использовать указатели, то можно сделать их следующим образом.

Так


dd 0
[[game.exe+3070A0]+68]+1e4: 

Или так


mov eax,[eax+68]
mov [eax+1e4],0
mov eax,[game.exe+3070a0] 

3. Ассемблерные инструкции

Ассемблерные инструкции.

Чтобы научиться писать скрипты нужно:

1) Учиться по примерам скриптов на нашем форуме или на форуме CE

2) Много практики

3) Читать справку CE, статьи и примеры. Хорошие статьи, но на английском можно найти также здесь.

О скриптах CE.

Скрипты CE обладают ограничениями. Сложно описать какими именно и в каких ситуациях, но один пример можно привести. Если Вам требуется чтобы скрипт изменялся в какой-то момент определённым образом например перед первым запуском, то вы НЕ сможете это сделать только скриптами Автоассемблера. Ну, может быть и можно в зависимости от ситуации - исправлять машинный код скрипта1 машинным кодом скрипта2 с помощью Автоассемблера. Однако, есть более удобное решение - LUA Engine. Информацию по LUA Engine вы сможете найти в соседней теме.

Ссылка на комментарий
Поделиться на другие сайты

  • 2 месяца спустя...

Как сделать чтобы узнать адрес инструкции (или как правильно сказать...) чтобы тот имел вид Process.exe+XXX. Process.exe это запущенная игра, ХХХ это смещение. Стандартно в автоассемблер списывается адрес без смещения.

Ссылка на комментарий
Поделиться на другие сайты

Можно перейти в отладчик по инструкции и нажать комбинацию: ctrl+M.

Либо печатаешь вручную, либо дальше добавляешь адрес инструкции из отладчика в таблицу CE и дважды кликаешь по нему, появится окошко из которого можно скопировать в буфер "Process.exe+XXX". Пока других способов нет.

Ссылка на комментарий
Поделиться на другие сайты

  • 1 год спустя...

Не знаю, ответят или нет, но спрашиваю:

А при замене куска памяти(Injection), если его можно включать и выключать, да и вообще, может произойти крэш?

Типа, прога обращается к адресу 004F2A12, а инжект в этот момент заменяет адреса с 004F2A00 по 004F2A20(допустим).

Я только второй день вплотную знакомлюсь со всей этой ассемблерной фигнёй, так что вопросов масса, но этот меня волнует больше всего.

Ещё вопрос: иногда случается крэш без видимой причины. Всё вроде работает, но при установке брейкпоинта и пошаговом выполнении иногда крэшится. В чём может быть причина?

Так всё работает идеально, а поставил брейкпоинт, пару циклов(и не обязательно пару, может вообще не вылететь, может вылететь сразу же) вручную запустил(ну в смысле кнопка Run, когда прога на брейкпоинте тормознёт), и крэш.

Ну и интересно было бы как добавить к float'ному значению float'ное же.

А то в eax что-то вроде 175.4727812, и добавть надо, допустим 3.4383

Читал статьи(где про FPU), но автоассемблер говорит что хрен бы знал чего я от него хочу...

Изменено пользователем Dark_XSM
Ссылка на комментарий
Поделиться на другие сайты

А при замене куска памяти(Injection), если его можно включать и выключать, да и вообще, может произойти крэш?

Типа, прога обращается к адресу 004F2A12, а инжект в этот момент заменяет адреса с 004F2A00 по 004F2A20(допустим).

Очень маловероятно что может произойти "крэш" процесса современной игры.

...иногда случается крэш без видимой причины. Всё вроде работает, но при установке брейкпомнта и пошаговом выполнении иногда крэшится. Это, кстати, тоже вопрос, в чём может быть причина?Так всё работает идеально, а поставил брейкпоинт, пару циклов(и не обязательно пару, может вообще не вылететь, может вылететь сразу же) вручную запустил(ну в смысле кнопко Run, когда прога на брейкпоинте тормознёт), и крэш.

Причина скорее в антиотладочной защите. В Cheat Engine есть режим VEH-дебегера в таких случаях. Но против некоторых версий Старфорса не поможет.

Ну и интересно было бы как добавить к float'ному значению float'ное же.

А то в eax что-то вроде 175.4727812, и добавть надо, допустим 3.4383

Читал статьи(где про FPU), но автоассемблер говорит что хрен бы знал чего я от него хочу...

Если я не ошибся, то где-то так:

[ENABLE]
//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048) //2kb should be enough
label(returnhere)
label(originalcode)
label(exit)
label(value)

newmem:
//....
push eax //eax = 175.4727812
fld dword [esp]
fadd dword [value]
fstp dword [esp]
pop eax // eax = eax + 3.4383
originalcode:
//...
exit:
jmp returnhere

value:
dd (float)3.4383

"Test.exe"+556DE:
jmp newmem
returnhere:



[DISABLE]
"Test.exe"+556DE:
mov eax,004546C0
//Alt: db B8 C0 46 45 00

dealloc(newmem)

Ссылка на комментарий
Поделиться на другие сайты

Хм... это бы конечно хорошо, но как это скрестить с тем что есть я не понял.

Есть вот что:

newmem:
pushf //на всякий
push ebx //в ebx строю указатель, в eax он уже есть
mov ebx,[[[some.dll+01249F10]+11]+200] //собсно, постройка указателя
add ebx,208 //всё ещё она...
cmp eax,ebx //сравнение того что у меня получилось с тем что записано в eax, ибо через это место единовременно считается примерно 200 переменных для разных адресов
jne originalcode //прыг если не то
add [eax],500000 //а если то, то, к примеру, добавить 500 тысяч обычных прям в память
movss xmm0,[eax] //запись из памяти в какое-то страшное место
originalcode:
pop ebx //восстановление ebx до чего-то там в диапозоне от 1 до 7
popf //восстановление "на всякий"
mov ecx,esi //неизвестная фигня
movss [eax],xmm0 //запись в память из какого-то страшного места
jmp returnhere

Именно тут вместо 500000 требуется нечто более точное, ибо в [eax] число с точкой, и требует точности, а то что я написал хоть и работает, но немного не так как хотелось бы.

mov ecx,esi сюда запихать пришлось потому что в месте внедрения не хватило места для джампа. Я не знаю что они делают.

P.S Я, кстати, думаю, что там где +500000 можно записывать не в память, а локально, но не знаю есть ли смысл. Быстродействие не страдает абсолютно, а для чего ещё менять запись?..

upd:

Вот до чего додумался за просмотром серии симпсонов(7-й сезон):

newmem:
pushf
push ebx
mov ebx,[[[[[p4dftre.dll+01849C8C]+24]+28]+128]+4]
add ebx,208
cmp eax,ebx
jne originalcode
fld dword [ebx]
fadd dword [value]
fstp dword [ebx]
movss xmm0,[ebx]
originalcode:
pop ebx
popf
mov ecx,esi
movss [eax],xmm0
jmp returnhere

value:
dd (float)1.0

Удивительно, но работает именно так как надо.

Благодарю за помощь.

Хоть я и не понял как работает вот это:

fld dword [esp]

fadd dword [value]

fstp dword [esp]

...

value:

dd (float)1.0

(это я к тому, что хотелось бы подробностей, как оно взаимосвязано, но самому смотреть лень)

Ссылка на комментарий
Поделиться на другие сайты

В какой-то игре случай с добавлением числа с точкой может быть разным и придётся писать инструкции иначе. Мой пример для всех игр не подходит и его нужно менять.

Попробую написать подробнее.


push eax //eax = 175.4727812
fld dword [esp]
fadd dword [value]
fstp dword [esp]
pop eax // eax = eax + 3.4383


push eax //eax уже предположительно равен 175.4727812 и его помещаем в стек в [esp]
fld dword [esp] // загружаем в ST0 значение 175.4727812 из стека
fadd dword [value] // добавляем к ST0 значение [value], меняется ST0
fstp dword [esp] // перезаписываем значение в стеке c выплёвываем из ST0 уже сумму
pop eax // eax = eax + 3.4383 // почти аналогично "выплёвываем" из стека сумму в eax

По поводу твоего примера, лучше не писать цепочку в скрипте типа mov ebx,[[[[[p4dftre.dll+01849C8C]+24]+28]+128]+4] и убрать лишние инструкции. Цепочку лучше так не писать, потому что она рассчитывает один раз и ассемблируется как mov ebx,[адрес]. А адрес в течении игры может быть другим! Может быть вылет из игры. Если есть полная цепочка указателей, то лучше не делать сравнений... И того получаем:

newmem:
pushf
mov ecx,[p4dftre.dll+01849C8C]
mov ecx,[ecx + 24]
mov ecx,[ecx + 28]
mov ecx,[ecx + 128]
mov ecx,[ecx + 4]
lea ecx,[ecx + 208] // ecx = [[[[[p4dftre.dll+01849C8C]+24]+28]+128]+4]+208

fld dword [value]
faddp dword [ecx]
movss xmm0,[ecx]

popf
mov ecx,esi
jmp returnhere

value:
dd (float)1.0

Может быть я где-то ошибся поэтому надо проверить в отладке. И ещё если знать работу с XMM-рами, то возможно можно ещё короче написать, т.к. в xmm0 в "младшей" части уже есть значение, к которому надо прибвить value.

Ссылка на комментарий
Поделиться на другие сайты

По поводу твоего примера, лучше не писать цепочку в скрипте типа mov ebx,[[[[[p4dftre.dll+01849C8C]+24]+28]+128]+4] и убрать лишние инструкции. Цепочку лучше так не писать, потому что она рассчитывает один раз и ассемблируется как mov ebx,[адрес]. А адрес в течении игры может быть другим! Может быть вылет из игры.
Если честно, не очень понял. Адрес же через указатели генерится... и если адрес которым будет оперировать игра не совпадёт с тем с которым планировалось, просто ничего не произойдёт... по моему...
Если есть полная цепочка указателей, то лучше не делать сравнений...
Эм... указатель-то вроде точный... но не делать сравнения, значит просто его туда дописать отдельно? Э... что-то я тут подвис. Там же куча переменных идёт, через xmm0, все разные, для разных адресов...

А в этом примере получается что любой адрес будет получать то что генерится в ecx

И кстати, почему ecx?

lea ecx,[ecx + 208]
Учтём.

P.S В общем, либо я туплю, либо чего-то не понимаю. В данной ситуации это немного разные вещи...

Ссылка на комментарий
Поделиться на другие сайты

Если честно, не очень понял. Адрес же через указатели генерится... и если адрес которым будет оперировать игра не совпадёт с тем с которым планировалось, просто ничего не произойдёт... по моему...

Если в течении игры адрес рассчитанный по цепочке указателей поменяется, то запись в него вызовет исключение времени выполнения, крах игры и сообщение об исключении. Если адрес за всю игру меняться не будет, то можно оставить цепочку указателей так как ты оформил. Проверить поменяется указательили нет, можно во время игры пройдя какую-то её часть. Если чит будет работать значит конечный адрес не поменялся.

Эм... указатель-то вроде точный... но не делать сравнения, значит просто его туда дописать отдельно? Э... что-то я тут подвис. Там же куча переменных идёт, через xmm0, все разные, для разных адресов...

А в этом примере получается что любой адрес будет получать то что генерится в ecx

И кстати, почему ecx?

Да, писать "отдельно", точнее встраивать новое условие записи в адрес через цепочку указателей в код игры.

Ну, куча переменных... надо так написать код, чтобы логика кода игры работала так как надо.

По ecx будет только тот адрес, который задан указателем. xmm0 и eax остаются в своём контексте выполнения кода, т.е. они равны значения без изменения.

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

Ссылка на комментарий
Поделиться на другие сайты

xmm0 используется там каждые 20-30 строк, при чём постоянно с записями типа movss xmm0,[какой-нить адрес], и movss [тот же адрес],xmm0

Предыдущий код я понял, в тот раз затупил из-за movss xmm0,[ecx], но без неё всё стало ясно.

Не совсем понял чем

mov ecx,[[[[[p4dftre.dll+01849C8C]+24]+28]+128]+4]
lea ecx,[ecx+208]

хуже

mov ecx,[p4dftre.dll+01849C8C]
mov ecx,[ecx + 24]
mov ecx,[ecx + 28]
mov ecx,[ecx + 128]
mov ecx,[ecx + 4]
lea ecx,[ecx + 208]

Одно и то же делают вроде?

Или это в целях повышения стабильности? Типа, "а вдруг!.."?

Но ведь если адрес поменяется, оба варианта окажутся не верными... и в случае сравнения вообще ничего не произойдёт, всё будет идти как раньше, вылета не будет.

Кстати, крэш.

Разбираюсь.

upd: помогла замена

fld dword [value]
faddp dword [ecx]

на

fld dword [ecx]
fadd dword [value]
fstp dwoed [ecx]

Работает, но выглядит ужасно(не код, а последствия его срабатывания).

Всё же оставлю сравнение, бывает когда изменение переменной нежелательно(оно само определяет, надо ли менять)

newmem:
pushf
mov ecx,[[[[[p4dftre.dll+01849C8C]+24]+28]+128]+4]
lea ecx,[ecx+208]
cmp eax,ecx
jne originalcode
fld dword [ecx]
fadd dword [value]
fstp dword [ecx]
movss xmm0,[ecx]
originalcode:
popf
mov ecx,esi
movss [eax],xmm0
jmp returnhere

Ссылка на комментарий
Поделиться на другие сайты

Одно и то же делают вроде?

Или это в целях повышения стабильности? Типа, "а вдруг!.."?

Не одно и тоже. Способ который я привёл рассчитывает указатель каждый раз заново, а твой - только при активации чита. Применять тот или иной способ зависит от кода игры. Посмотри в дизассемблере что у тебя получается при активации чита. Так же советую это делать почаще для версии CE 6.1, т.к. она может неправильно ассемблировать.

По поводу вылета на "faddp dword [ecx]". У меня вообще эта инструкция не ассемблировалась. Похоже она работает только с регистрами FPU.

Ссылка на комментарий
Поделиться на другие сайты

MasterGH а реально вызывать процедуры из CE по горячей клавише? Допустим при внедрении DLL можно вызвать фунцию из неё ... хотелось бы без DLL так же вызывать произвольную функцию в игре

Ссылка на комментарий
Поделиться на другие сайты

Посмотри в дизассемблере что у тебя получается при активации чита.
Понял.

И ещё вопрос возник. Не совсем по этой теме...

Я так понял, на LUA можно несколько удобнее сделать?

Там же во время выполнения можно менять переменные по горячим клавишам, таким образом включая/отключая разные секции кода?

Тогда получается что в моём случае можно было бы менять сразу несколько переменных, включая и отключая любые из них, не трогая остальные(записывающиеся в адреса), а в автоассемблере есть только варианты вкл/выкл вообще всего...

Жаль что из программирования я тока про Паскаль чего-то помню, и про Java Script

Ссылка на комментарий
Поделиться на другие сайты

MasterGH а реально вызывать процедуры из CE по горячей клавише? Допустим при внедрении DLL можно вызвать фунцию из неё ... хотелось бы без DLL так же вызывать произвольную функцию в игре

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


function FunctionSpawnCar(hotkey)
autoAssemble("CREATETHREAD(SpawnCar)")
end

function SetHotKey(func, hotkey)
local objectHotKey = createHotkey(func, hotkey)
generichotkey_setKeys(objectHotKey, hotkey)
generichotkey_onHotkey(objectHotKey, func)
end

function Deinitialization()
autoAssemble([[
unregistersymbol(SpawnCar)
dealloc(SpawnCar)
]])
end

function Initialization()

local address = ... // получить адрес вызываемой функции

local AAscript = [[
alloc(SpawnCar,2048)
registersymbol(SpawnCar)
label(stringCar)

SpawnCar:
push ...
push ...
push stringCar
call ]]..address..[[
ret

stringCar:
db ... 00 // hex-строка машины оканчивающаясь нулевым символом
]]

autoAssemble(AAscript)

--создание формы трейнера
-- ...

--привязка функции Deinitialization() к закрытию формы
-- ...

--Назначение хоткеев
setHotKey(FunctionSpawnCar, VK_F2) -- спавн некоторой машины
end

function onOpenProcess(processid)
Initialization()
end

local aalist = getAutoAttachList()
stringlist_add(aalist, "gta4.exe")

Как видно здесь Lua код вперемешку с Автоассемблером. Есть инициализация, деинициализация, првязка горячей клавиши, создание потока на АА. Могут быть проблемы с поточной синхронизацией или другие, надо проверять на практике...

Понял.

И ещё вопрос возник. Не совсем по этой теме...

Я так понял, на LUA можно несколько удобнее сделать?

Там же во время выполнения можно менять переменные по горячим клавишам, таким образом включая/отключая разные секции кода?

Тогда получается что в моём случае можно было бы менять сразу несколько переменных, включая и отключая любые из них, не трогая остальные(записывающиеся в адреса), а в автоассемблере есть только варианты вкл/выкл вообще всего...

Жаль что из программирования я тока про Паскаль чего-то помню, и про Java Script

1. Можно ли на Lua делать удобнее не знаю. Для каждого человека своё видение удобства.

2. По горячим клавишам можно выполнять Lua функцию, которая могла бы на АА скриптах что-то делать... создавать новые "секции кода" и уничтожать старые.

3. Переменные можно менять и без Lua. Зарегистрируй их в АА через registersymbol. Создай другой АА который бы менял значения по зарегистрированным меткам.

4. Когда Lua поддержки в CE не было у меня была та же проблема. Lua я не знал, но учился на примерах.

  • Плюс 1
Ссылка на комментарий
Поделиться на другие сайты

Ещё вопрос имеется.

Есть несколько строк типа "repe movsd", в которых происходит что-то страшное.

Мне в это надо вмешаться, и что-то подправить, но я не представляю как, и что...

Как оно работает, и как вмешаться в её работу?

Там что-то происходит, с участием адреса 306F962C (хотя скорее не он нужен), надо что бы этого не происходило.

upd: думаю, это важно.

Во время работы этой строки меняются esi и edi, с шагом 4 байта, и ecx с шагом 1

00000184

306F9268

01B2F610

...

00000183

306F926C

01B2F614

Ссылка на комментарий
Поделиться на другие сайты

"repe movsd" циклически перемещает данные 4-х байт из адреса EDI+ecx*4 в адрес ESI+ecx*4 уменьшая указанный ecx на единицу до тех пор пока ecx не будет равен нулю.

Ссылка на комментарий
Поделиться на другие сайты

Не знаю где спросить, а ИНет почему-то сильно тормозит, и просмотр тем куда надо писать может занять до 30 минут, так что спрашиваю тут:

Нельзя ли поставить брейкпоинт так, что бы он срабатывал только тогда, когда число в адресе становится равным, к примеру, 5 ?

Я не знаю как сформулировать вопрос, так что опишу ситуацию:

Есть некий адрес, который используется для хранения самых разных значений, в том числе и нужного мне.

Обращений к адресу примерно 1000 в секунду, примерно с 600 разных мест.

И какое-то из обращений пишет в адрес цифру 5

Можно как-то просто узнать, где она пишется, а не проверять каждую из 600 функций вручную?

Ссылка на комментарий
Поделиться на другие сайты

В CE 6.1 я ставил условные бряки на конкретные значения в регистрах так. Сначала F5 ставит обычый бряк, потом правой кнопкой на бряке "Назначить\Изменить условия точки останова" и писал к примеру EBX==0x0E1244 (простое условие). Бряк срабатывал только когда в EBX проскакивало 0E1244. С обычными адресами не пробовал, но может быть можно задать условие вида "0xADDRESS==5"? Не уверен что синтаксис верен...

Ссылка на комментарий
Поделиться на другие сайты

5 флоатная, выглядит как 40A00000

"0xADDRESS" уже пробовал.

Можно бы вычислить по обращениям в период между началом загрузки, и записью значения в постоянное место, но почему-то условие типа ((ESP == 0x0012FABC) and (EDI == 0x40A00000)) не срабатывает.

А иначе я задолбаюсь кнопку продолжения тыкать.

Ссылка на комментарий
Поделиться на другие сайты

  • 11 месяцев спустя...

Привет! Использовал раньше вставки ассемблера для стационарных адресов, а сейчас понадобилось для адреса, найденного с помощью аобскан. Как быть?

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

Вот пример:


results=AOBScan("83 C4 10 F3 0F 7E 4D D8 66 0F 57 C0 F2 0F 2A C0 F2 0F 59 C8 66 0F D6 4D E0","+X-W-C")
count=stringlist_getCount(results)
address_aob1 =getAddress(stringlist_getString(results,0))

workTemplateAsmText1 = [[
alloc(newmem,2048) //2kb should be enough
label(returnhere)
label(originalcode)
label(exit)
newmem: //this is allocated memory, you have read,write,execute access
//place your code here
originalcode:
mulsd xmm1,xmm0
mov [ebp-20],00000000

exit:
jmp returnhere
]]..address_aob1..[[
jmp newmem
nop
nop
nop
nop
returnhere: ]]
autoAssemble(workTemplateAsmText1)

Ссылка на комментарий
Поделиться на другие сайты

×
×
  • Создать...

Важная информация

Находясь на нашем сайте, Вы автоматически соглашаетесь соблюдать наши Условия использования.