MasterGH

Частые ошибки и редкие пакостные сюрпризы

16 сообщений в этой теме

Частые ошибки

1) Сначала создайте память под тело и напишите в ней код чит-кода, а затем пишите прыжок на адрес выделенной памяти

2) Сначала отмените прыжок, а затем уничтожайте выделенную память

3) Если у Вас codecave в уже существующей памяти, то сначала в codecave напишите код, а затем делайте на codecave прыжок

4) Будьте внимательны в расчёте количества нопов

5) Будьте внимательны с логикой кода, вы не должны вызывать крах игры

Редкие и пакостные моменты при внедрении чит-кодов

1) При внедрении чит-кода нужно следить за регистром флагов. Если он потребуется при выходе из выделенной памяти,то условие не будет правильно выполняться. Выход - поставить pushfd перед сравнениями в выделенной памяти и поставить popfd при выходе из выделенной памяти.

2) Ещё очень важное редкое явление, когда на затёртые инструкции оригинального кода могут уже быть прыжки. Т.е. на инструкции где вы ставили nop-s могут быть прыжки. Будет крах игры если какое-то условие не выполниться по логике кода.

3) Этот касается "острых" моментов, таких где происходят манипуляции со стеком. Учитывайте что call кладёт в стек адрес для обратного вызова по ret. А это значит что сдвигаются смещения по esp внутри тела чит-кода и могут сдвинуться по ebp. У Xipho была статья об этом, точно не помню. Соответственно нужно обращать внимание ещё и когда вы вызываете ret и кладёте в стек что-то.

4) Данные помещаемые в регистры XMM должны быть кратны 16 байтам! Иначе могут быть глюки с изображением в игре.

5) Если у Вас неправильно работает скрипт и игра тут же закрывается с критической ошибкой, то у вас есть все инструменты (отладчики) чтобы проверить логику и ошибку. Поставьте игру в конный режим (или сделайте его по нашим статьям) и проведите пошаговую отладку. Не знаете как это сделать, то задайте вопрос на форуме.

1

Поделиться сообщением


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

Примеры скриптов с возможными ошибками пользователей.

1. Случай.

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

Ниже скрипт постоянное, здоровье возвращает герою здоровье.


[ENABLE]
alloc(newmem,256)
label(back)
label(code)

019FAB50:
jmp newmem
back:

newmem:
push eax
cmp byte ptr [ecx],a0
jne code
mov eax,[ecx+1a]
mov [ecx+16],eax

code:
pop eax
fld dword ptr [ecx+16]
ret
int 3
jmp back

[DISABLE]
dealloc(newmem)
019FAB50:
fld dword ptr [ecx+16]
ret
int 3

Скорее всего, правильнее написать так (без учёта сохранения/восстановления регистра флагов):


alloc(newmem,256)
label(code)

newmem:
cmp byte [ecx],a0
jne code
fld dword [ecx+1a]
ret
code:
fld dword [ecx+16]
ret


019FAB50:
jmp newmem


[DISABLE]

019FAB50:
fld dword ptr [ecx+16]
ret
int 3

dealloc(newmem)
[ENABLE]

С восстановлением флагов было бы так:


alloc(newmem,256)
label(code)

newmem:
pushfd
cmp byte [ecx],a0
jne code
fld dword [ecx+1a]
popfd
ret
code:
fld dword [ecx+16]
popfd
ret


019FAB50:
jmp newmem


[DISABLE]

019FAB50:
fld dword ptr [ecx+16]
ret
int 3

dealloc(newmem)
[ENABLE]

Напоминаю, что сохранять и восстанавливать флаги нужно в тех случаях, когда после вашей инъекцией кода и идёт код использующий регистр флагов. Чаще всего это инструкции инструкции cmp и test. Если будут таки команды, то возможно будет вылет из игры.
0

Поделиться сообщением


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

2. Случай.

Увлёкшись написанием длинного скрипта можно забыть о корректности типов данных. В этом примере не учтено, что cmp без указания типа данных сравнивает данные как dword. Это касается 32-х разрядных приложений.


//code from here to '[DISABLE]' will be used to enable the cheat
alloc(newmem,2048) //2kb should be enough
label(GM1)
label(GM2)
label(nocops)
label(returnhere)
label(originalcode)
//label(pBuffer)
label(money)
label(god)
label(armor)
label(cops)
//registersymbol(pBuffer)
registersymbol(money)
registersymbol(god)
registersymbol(armor)
registersymbol(cops)
label(exit)

newmem: //this is allocated memory, you have read,write,execute access
//place your code here
cmp ebx,0 //первый фильтр на буфер с розыском
jne originalcode
cmp edx,2000 //второй фильтр на буфер с розыском
jne originalcode
//mov [pBuffer],ecx
cmp esi,3 //третий фильтр на буфер с розыском
jne originalcode
cmp [money],01 //+1000000$?
jne GM1
mov [ecx+90],#100000

GM1:
cmp [god],01 //беск. здоровье вкл.?
jne GM2
//mov [ecx+22D0],(float)10000 //столько здоровья хватит, чтобы не взрываться в машинах
mov [ecx+510],(float)10000
GM2:
cmp [armor],01 //беск. броня вкл.?
jne nocops
//mov [ecx+2290],(float)1000

nocops:
cmp [cops],01 //убрать звезды розыска вкл.?
jne originalcode
mov [ecx+10],00 //нет звёзд

originalcode:
lea eax,[esp]
push eax
push 00

exit:
jmp returnhere

//pBuffer:
//db 0
money:
db 0
god:
db 0
armor:
db 0
cops:
db 0

"EFLC.exe"+8F1E3:
jmp newmem
nop
returnhere:




[DISABLE]
//code from here till the end of the code will be used to disable the cheat
dealloc(newmem)
//unregistersymbol(pBuffer)
unregistersymbol(money)
unregistersymbol(god)
unregistersymbol(armor)
unregistersymbol(cops)

"EFLC.exe"+8F1E3:
lea eax,[esp]
push eax
push 00
//Alt: db 8D 04 24 50 6A 00
[ENABLE]

Для того чтобы скрипт работал как надо, проще объявить сравниваемый тип данных не как db, а как dd.

0

Поделиться сообщением


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

3. Случай

Игра вылетает и ошибка в скрипте абсолютная не узнаваема. Что делать?!

Используйте отладчик CheatEngine с пошаговым выполнением.

Например у вас такой скрипта


[ENABLE]
alloc(newmem,2048)
label(returnhere)
label(originalcode)
label(exit)

newmem:
cmp [esi+0000038c],0
jne short originalcode
mov eax,#999
originalcode:
mov [edi],eax
mov edi,eax
mov eax,[esp+14]
exit:
jmp returnhere

101337F4:
jmp newmem
nop
nop
nop
returnhere:

[DISABLE]
dealloc(newmem)
101337F4:
mov [edi],eax
mov edi,eax
mov eax,[esp+14]
//Alt: db 89 07 8B F8 8B 44 24 14

1) Поставить игру в оконный режим

2) На инструкции выше адреса 0x101337F4нажать на F5 в дизассемблере. (это установка брейкпоинта на выполнение кода, зелёное выделение)

2) Сделать в игре что-нибудь чтобы игра прервалась на брейкпоинте.

3) Активировать скрипт Автоассемблера.

4) Нажимать F7 и смотреть регистры.

5) Запомнить инструкцию перед крахом игры. Проанализировать. Изменить скрипт.

Если вылета нет, то при выходе из тела чита нажать F9 чтобы "отпустить" процесс.

Чтобы снять брейкпоинт выделить зелёную инструкцию и нажать F5.

Стоит запомнить. Отладчик специально создан для того чтобы отлавливать ошибки кода. В том числе и отлавливать ошибки ваших скриптов.

0

Поделиться сообщением


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

Случа4 и Случай5

Чтение(или запись) из не существующего адреса (или адреса с протекцией памяти не для чтения) и случай выполнения перемещённой инструкции.

ANT' date='27 Май 2011 - 00:04' timestamp='1306440261' post='3117']

Можно всегда сразу с ebx (или др. выбранным регистром) сравнивать. Просто я привык по шаблону делать.

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

только такой вариант у меня нормально работает


[ENABLE]
alloc(newmem,2048)
label(vitality)
label(returnhere)
label(originalcode)

newmem:
vitality:
push ebx
mov ebx,[witcher2.exe+022BC5F4]
mov ebx,[ebx+14]
mov ebx,[ebx+14]
mov ebx,[ebx+8]
cmp [eax],ebx
pop ebx
jne short originalcode
push esi
mov esi,[witcher2.exe+022BC5F4]
mov esi,[esi+14]
mov esi,[esi+14]
mov esi,[esi+0C]
mov [eax],esi
pop esi
originalcode:
fld dword ptr [eax]
mov eax,[ebp+08]
jmp returnhere

witcher2.exe+8CA4:
jmp vitality
returnhere:

[DISABLE]
dealloc(newmem)

witcher2.exe+8CA4:
fld dword ptr [eax]
mov eax,[ebp+08]

Скрипт работает нормально но при переходе в другой уровень игры, (в локации при загрузках) игра вылетает.

Возможные причины:

1) По этому указателю:


mov ebx,[witcher2.exe+022BC5F4]
mov ebx,[ebx+14]
mov ebx,[ebx+14] // например в скобках оказался не существующий адрес и вызвало крах игры
mov ebx,[ebx+8]

где-то на уровнях отсутствует указатель, например, там где [ebx+8] бывает ноль. Чтение этого значения вызовет вылет. Чтобы этого не было, нужно проверять указатели.

2) Причина, может быть вызов перемещённой инструкции:


witcher2.exe+8CA4:
fld dword ptr [eax]
mov eax,[ebp+08] // например код пытался вызвать эту перемещённую инструкцию

0

Поделиться сообщением


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

Частые ошибки

 Редкие и пакостные моменты при внедрении чит-кодов

MasterGH, прекрасная статья, по-моему я уже столкнулся со всеми перечисленными тобой случаями, жаль, что раньше не встречал эту статью.

0

Поделиться сообщением


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

Как бороться с вот этим?

Цитата

Чтение(или запись) из не существующего адреса (или адреса с протекцией памяти не для чтения) и случай выполнения перемещённой инструкции.

 

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

Изменено пользователем DarkPower2
0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
38 минуты назад, DarkPower2 сказал:

указатель на него меняется на несуществующий адрес.

Выложи свой скрипт, посмотрим что можно сделать.

А так - нужно дополнительно фильтровать в скрипте - делать проверку.

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
6 часов назад, Garik66 сказал:

Выложи свой скрипт, посмотрим что можно сделать.

А так - нужно дополнительно фильтровать в скрипте - делать проверку.

 

Скрытый текст

newmem:
originalcode:
mov R13, ["server.dll"+01C508B8] //вот тут бывакт
mov R13, [R13]
mov R13, [R13+48]
cmp rbx, [R13]
je exit
movss [rbx+000007EC],xmm7

exit:
movss xmm1, [rbx+7EC]
jmp returnhere

"server.dll"+884A2A:
push RDI
mov RDI, newmem
jmp RDI
nop
nop
returnhere:
pop RDI

 

 

0

Поделиться сообщением


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

Замечания по скрипту:

1. Ты не сохраняешь регистр R13 в стеке, я имею ввиду:

push r13
......
pop r13

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

2. Ты смело пишешь инструкцию:

add R13, 590
cmp rbx, [R13]

лучше сделать так:

cmp rbx, [R13+590]

3. 

mov R13, ["server.dll"+01C508B8] //вот тут бывакт

А какие бывают значения? Адрес же по идее статичный.

Нужно найти инструкцию, которая работает с этим адресом, из неё найти адреса с которыми она работает и сделать фильтр только для твоего адреса.

0

Поделиться сообщением


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

Я изменил код.

Ну вобще в конце указателя бывает.

Разве не сохраняется R13?

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
1 минуту назад, DarkPower2 сказал:

Разве не сохраняется R13?

В твоём скрипте нет.

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Только что, Garik66 сказал:

В твоём скрипте нет.

Ай, блин... Просто неверный код скинул. Я потерял тот, это тестовый я делал... щас отредактирую...

0

Поделиться сообщением


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

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

Скрытый текст

newmem:
push R13
mov R13, ["server.dll"+01C508B8]
mov R13, [R13]
mov R13, [R13+48]
cmp rbx, [R13]
je exit
movss [rbx+000007EC],xmm7

exit:
pop R13
movss xmm1, [rbx+7EC]
jmp returnhere

"server.dll"+884A2A:
push RDI
mov RDI, newmem
jmp RDI
nop
nop
returnhere:
pop RDI

 

 

0

Поделиться сообщением


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

1. Под спойлер.

2. Выкладывайте лучше весь скрипт (лучше с листингом инструкций внизу скрипта, который делает СЕ).

3. А скрипт у тебя точно рабочий? Просто, если оригинальная инструкция например эта:

movss xmm1, [rbx+7EC]

то наверное нужно не 

je exit

а

jne exit

 Ладно ещё раз попрощаюсь - поздно уже.

0

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Цитата

3. А скрипт у тебя точно рабочий? Просто, если оригинальная инструкция например эта:

Там 2 оригинальных инструкции... просто если персонаж совпадает с моим, то пропускается одна инструкция. 

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

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

0

Поделиться сообщением


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

Создайте аккаунт или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать аккаунт

Зарегистрируйтесь для получения аккаунта. Это просто!


Зарегистрировать аккаунт

Войти

Уже зарегистрированы? Войдите здесь.


Войти сейчас