-
Постов
2 999 -
Зарегистрирован
-
Победитель дней
129
Тип контента
Профили
Форумы
Загрузки
Блоги
Сообщения, опубликованные MasterGH
-
-
aliast, замени там где надо db на dd или поставь тип данных байта в сравнении. По умолчанию в 32-разрядных приложениях сравниваются значения типа dword-а. Поэтому такой эффект.
-
Ой. Инструкцию "movss xmm0,[ecx]" надо убрать. По идеи xmm0 дальше использоваться не будет. А если будет, то надо по другому написать.
-
Если честно, не очень понял. Адрес же через указатели генерится... и если адрес которым будет оперировать игра не совпадёт с тем с которым планировалось, просто ничего не произойдёт... по моему...
Если в течении игры адрес рассчитанный по цепочке указателей поменяется, то запись в него вызовет исключение времени выполнения, крах игры и сообщение об исключении. Если адрес за всю игру меняться не будет, то можно оставить цепочку указателей так как ты оформил. Проверить поменяется указательили нет, можно во время игры пройдя какую-то её часть. Если чит будет работать значит конечный адрес не поменялся.
Эм... указатель-то вроде точный... но не делать сравнения, значит просто его туда дописать отдельно? Э... что-то я тут подвис. Там же куча переменных идёт, через xmm0, все разные, для разных адресов...А в этом примере получается что любой адрес будет получать то что генерится в ecx
И кстати, почему ecx?
Да, писать "отдельно", точнее встраивать новое условие записи в адрес через цепочку указателей в код игры.
Ну, куча переменных... надо так написать код, чтобы логика кода игры работала так как надо.
По ecx будет только тот адрес, который задан указателем. xmm0 и eax остаются в своём контексте выполнения кода, т.е. они равны значения без изменения.
ecx я взял, потому что в него в оригинальном коде будет все равно перезапись из esi. А это значит, что ecx "свободная переменная" для наших действий до оригинального кода.
-
В какой-то игре случай с добавлением числа с точкой может быть разным и придётся писать инструкции иначе. Мой пример для всех игр не подходит и его нужно менять.
Попробую написать подробнее.
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.
-
Попробуй сделать следующее. Запусти его трейнер чтобы тот уже работал с игрой. Подключись к процессу трейнера procxp.exe. Найди процесс трейнера (или один из нескольких процессов), выдели его и спосмотри в его свойствах строки. Попробуй через ctrl+f ввести строки из предполагаемого скрипта. Например введи "ENABLE"... возможно у тебя получиться увидеть скрипты на CE, если они будут в памяти процесса.
-
А ну теперь ясна первостепенная задача. А ты не смотрел таблицы на официальном сайте Cheat Engine, может быть ты там найдёшь подсказку?!
-
А что в этом трейнере особенного, раз ты взялся за его распаковку?
-
А при замене куска памяти(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) -
Очевидно, что у другой игры может быть другой случай
Чтобы найти решение нужно кропотливо сидеть и "ковыряться" в коде и данных игрового процесса.
-
Akama, не спешил бы ты с выводами так скоро и при любой возможности. Вот практическое применение.
Как видно на рисунке указатели были исследованы, а вот как сделать "бесконечное обучение заклинаниям" будет описано ниже благодаря способу о котором идёт речь. Этот способ установил рамки до какого адреса вверх стоит подниматься из call-ов.
Более подробно про то как сделать бесконечное обучение заклинаниям.
1. Вникаем в суть игры и интерфейс, что не мало важно.
Во время изучения заклинания происходят следующие действия.
- В книге заклинаний выбираем заклинание
- Щёлкаем по кнопке выучить заклинания и только после того как отпустили кнопку ,то вычитается мана и заклинания выучено.
2. Раз знаем суть процесса, то находим адрес маны и ставим аппаратный бряк на запись.
3. Ставим бряк на обработку сообщения на WM_MousUp.
Щелкаем на кнопке заклинаний, прерываемся на адресе работы с сообщением.
Снимаем бряк с сообщений и отпускает трейс по ретам.
Возвращаемся в игру.
Происходит прерывание на бряке маны. Снимаем бряк. Отпускаем игру и тут же находимся на развилке кода, это место можно считать верхнем порогом кода. Т.е. выше него мы дальше не полезем.
Итак, определили путь.
Начало пути - нажали на кнопку:
0040657B . E8 A0D0FFFF CALL Disciple.00403620 - будет началом возможно закрученного пути.
Конец - вычитание маны:
0065AA15 |. 8910 MOV DWORD PTR [EAX],EDX – конечный путь
Вновь ставим бряк на запись маны, прерываемся.
Теперь мы идем вверх по коду пробегая его глазами, если что-то не находим,то идём выше, каждый раз поднимаясь на уровень выше отмечаем адреса входа в комментариях. Но идти вверх по коду далеко не пришлось. Мы поднялись на один уровень и оказались в этой функции.
006CF6DA |. 75 33 JNZ SHORT Disciple.006CF70F //можно исправить на JMP как это сделал SERGANT
006CF6DC |. 8B01 MOV EAX,DWORD PTR [ECX]
006CF6DE |. 6A 00 PUSH 0
006CF6E0 |. 6A 01 PUSH 1
006CF6E2 |. 68 A8A47F00 PUSH Disciple.007FA4A8 ; ASCII "Msg_SpellTooMuch"
006CF6E7 |. 68 FCA17F00 PUSH Disciple.007FA1FC ; ASCII "Msg_HLIngfo"
006CF6EC |. FF90 58020000 CALL NEAR DWORD PTR [EAX+258]
006CF6F2 |. 8B0D A478C301 MOV ECX,DWORD PTR [1C378A4]
006CF6F8 |. 8B11 MOV EDX,DWORD PTR [ECX]
006CF6FA |. 68 0000803F PUSH 3F800000
006CF6FF |. 6A 18 PUSH 18
006CF701 |. FF92 BC040000 CALL NEAR DWORD PTR [EDX+4BC]
006CF707 |. 5F POP EDI ; 25F89E08
006CF708 |. 32C0 XOR AL,AL
006CF70A |. 5D POP EBP ; 25F89E08
006CF70B |. 83C4 10 ADD ESP,10
006CF70E |. C3 RET
006CF70F |> 8B87 74010000 MOV EAX,DWORD PTR [EDI+174]
006CF715 |. 3B87 30010000 CMP EAX,DWORD PTR [EDI+130]
006CF71B |. 73 0B JNB SHORT Disciple.006CF728
006CF71D |. 8B8F 2C010000 MOV ECX,DWORD PTR [EDI+12C]
006CF723 |. 8D0481 LEA EAX,DWORD PTR [ECX+EAX*4]
006CF726 |. EB 06 JMP SHORT Disciple.006CF72E
006CF728 |> 8D87 3C010000 LEA EAX,DWORD PTR [EDI+13C]
006CF72E |> 8B10 MOV EDX,DWORD PTR [EAX]
006CF730 |. 53 PUSH EBX
006CF731 |. 8B1A MOV EBX,DWORD PTR [EDX]
006CF733 |. E8 18E1FFFF CALL Disciple.006CD850
006CF738 |. 84C0 TEST AL,AL
006CF73A |. 74 09 JE SHORT Disciple.006CF745
006CF73C |. 5B POP EBX ; 25F89E08
006CF73D |. 5F POP EDI ; 25F89E08
006CF73E |. 32C0 XOR AL,AL
006CF740 |. 5D POP EBP ; 25F89E08
006CF741 |. 83C4 10 ADD ESP,10
006CF744 |. C3 RET
006CF745 |> 56 PUSH ESI
006CF746 |. 8BB7 74010000 MOV ESI,DWORD PTR [EDI+174]
006CF74C |. 33C9 XOR ECX,ECX
006CF74E |. 8D5D 04 LEA EBX,DWORD PTR [EBP+4]
006CF751 |> 3BB7 30010000 /CMP ESI,DWORD PTR [EDI+130]
006CF757 |. 73 0B |JNB SHORT Disciple.006CF764
006CF759 |. 8B87 2C010000 |MOV EAX,DWORD PTR [EDI+12C]
006CF75F |. 8D04B0 |LEA EAX,DWORD PTR [EAX+ESI*4]
006CF762 |. EB 06 |JMP SHORT Disciple.006CF76A
006CF764 |> 8D87 3C010000 |LEA EAX,DWORD PTR [EDI+13C]
006CF76A |> 8B10 |MOV EDX,DWORD PTR [EAX]
006CF76C |. 3B4A 24 |CMP ECX,DWORD PTR [EDX+24]
006CF76F |. 0F83 87000000 |JNB Disciple.006CF7FC
006CF775 |. 3BB7 30010000 |CMP ESI,DWORD PTR [EDI+130]
006CF77B |. 73 0B |JNB SHORT Disciple.006CF788
006CF77D |. 8B87 2C010000 |MOV EAX,DWORD PTR [EDI+12C]
006CF783 |. 8D04B0 |LEA EAX,DWORD PTR [EAX+ESI*4]
006CF786 |. EB 06 |JMP SHORT Disciple.006CF78E
006CF788 |> 8D87 3C010000 |LEA EAX,DWORD PTR [EDI+13C]
006CF78E |> 8B00 |MOV EAX,DWORD PTR [EAX]
006CF790 |. 8B50 24 |MOV EDX,DWORD PTR [EAX+24]
006CF793 |. 83C0 20 |ADD EAX,20
006CF796 |. 3BCA |CMP ECX,EDX
006CF798 |. 73 07 |JNB SHORT Disciple.006CF7A1
006CF79A |. 8B10 |MOV EDX,DWORD PTR [EAX]
006CF79C |. 8D048A |LEA EAX,DWORD PTR [EDX+ECX*4]
006CF79F |. EB 03 |JMP SHORT Disciple.006CF7A4
006CF7A1 |> 83C0 10 |ADD EAX,10
006CF7A4 |> 83F9 FF |CMP ECX,-1
006CF7A7 |. 8B00 |MOV EAX,DWORD PTR [EAX]
006CF7A9 |. 74 09 |JE SHORT Disciple.006CF7B4
006CF7AB |. 83F9 08 |CMP ECX,8
006CF7AE |. 7D 04 |JGE SHORT Disciple.006CF7B4
006CF7B0 |. 8B13 |MOV EDX,DWORD PTR [EBX]
006CF7B2 |. EB 03 |JMP SHORT Disciple.006CF7B7
006CF7B4 |> 83CA FF |OR EDX,FFFFFFFF
006CF7B7 |> 3BD0 |CMP EDX,EAX
006CF7B9 |. 7C 06 |JL SHORT Disciple.006CF7C1
006CF7BB |. 41 |INC ECX
006CF7BC |. 83C3 0C |ADD EBX,0C
006CF7BF |.^ EB 90 \JMP SHORT Disciple.006CF751
006CF7C1 |> 8B0D A478C301 MOV ECX,DWORD PTR [1C378A4]
006CF7C7 |. 8B01 MOV EAX,DWORD PTR [ECX]
006CF7C9 |. 6A 00 PUSH 0
006CF7CB |. 6A 01 PUSH 1
006CF7CD |. 68 F0A17F00 PUSH Disciple.007FA1F0 ; ASCII "Msg_NoRes"
006CF7D2 |. 68 FCA17F00 PUSH Disciple.007FA1FC ; ASCII "Msg_HLIngfo"
006CF7D7 |. FF90 58020000 CALL NEAR DWORD PTR [EAX+258]
006CF7DD |. 8B0D A478C301 MOV ECX,DWORD PTR [1C378A4]
006CF7E3 |. 8B11 MOV EDX,DWORD PTR [ECX]
006CF7E5 |. 68 0000803F PUSH 3F800000
006CF7EA |. 6A 18 PUSH 18
006CF7EC |. FF92 BC040000 CALL NEAR DWORD PTR [EDX+4BC]
006CF7F2 |. 5E POP ESI ; 25F89E08
006CF7F3 |. 5B POP EBX ; 25F89E08
006CF7F4 |. 5F POP EDI ; 25F89E08
006CF7F5 |. 32C0 XOR AL,AL
006CF7F7 |. 5D POP EBP ; 25F89E08
006CF7F8 |. 83C4 10 ADD ESP,10
006CF7FB |. C3 RET
006CF7FC |> 8B4424 10 MOV EAX,DWORD PTR [ESP+10]
006CF800 |. 33ED XOR EBP,EBP
006CF802 |. 33DB XOR EBX,EBX
006CF804 |> 8B8F 30010000 /MOV ECX,DWORD PTR [EDI+130]
006CF80A |. 894424 14 |MOV DWORD PTR [ESP+14],EAX
006CF80E |. 8B87 74010000 |MOV EAX,DWORD PTR [EDI+174]
006CF814 |. 3BC1 |CMP EAX,ECX
006CF816 |. 896C24 1C |MOV DWORD PTR [ESP+1C],EBP
006CF81A |. 73 0B |JNB SHORT Disciple.006CF827
006CF81C |. 8B8F 2C010000 |MOV ECX,DWORD PTR [EDI+12C]
006CF822 |. 8D0C81 |LEA ECX,DWORD PTR [ECX+EAX*4]
006CF825 |. EB 06 |JMP SHORT Disciple.006CF82D
006CF827 |> 8D8F 3C010000 |LEA ECX,DWORD PTR [EDI+13C]
006CF82D |> 8B11 |MOV EDX,DWORD PTR [ECX]
006CF82F |. 3B6A 24 |CMP EBP,DWORD PTR [EDX+24]
006CF832 |. 0F83 A7000000 |JNB Disciple.006CF8DF
006CF838 |. 3B87 30010000 |CMP EAX,DWORD PTR [EDI+130]
006CF83E |. 73 0B |JNB SHORT Disciple.006CF84B
006CF840 |. 8B8F 2C010000 |MOV ECX,DWORD PTR [EDI+12C]
006CF846 |. 8D0481 |LEA EAX,DWORD PTR [ECX+EAX*4]
006CF849 |. EB 06 |JMP SHORT Disciple.006CF851
006CF84B |> 8D87 3C010000 |LEA EAX,DWORD PTR [EDI+13C]
006CF851 |> 8B00 |MOV EAX,DWORD PTR [EAX]
006CF853 |. 8B48 24 |MOV ECX,DWORD PTR [EAX+24]
006CF856 |. 83C0 20 |ADD EAX,20
006CF859 |. 3BE9 |CMP EBP,ECX
006CF85B |. 73 06 |JNB SHORT Disciple.006CF863
006CF85D |. 8B00 |MOV EAX,DWORD PTR [EAX]
006CF85F |. 03C3 |ADD EAX,EBX
006CF861 |. EB 03 |JMP SHORT Disciple.006CF866
006CF863 |> 83C0 10 |ADD EAX,10
006CF866 |> 83FB FC |CMP EBX,-4
006CF869 |. 8B00 |MOV EAX,DWORD PTR [EAX]
006CF86B |. 74 62 |JE SHORT Disciple.006CF8CF
006CF86D |. 83FB 20 |CMP EBX,20
006CF870 |. 7F 5D |JG SHORT Disciple.006CF8CF
006CF872 |. 8B5424 14 |MOV EDX,DWORD PTR [ESP+14]
006CF876 |. 8B32 |MOV ESI,DWORD PTR [EDX]
006CF878 |. 8B5424 10 |MOV EDX,DWORD PTR [ESP+10]
006CF87C |. 8D4C24 18 |LEA ECX,DWORD PTR [ESP+18]
006CF880 |. 51 |PUSH ECX
006CF881 |. 6A 00 |PUSH 0
006CF883 |. F7D8 |NEG EAX
006CF885 |. 50 |PUSH EAX
006CF886 |. 56 |PUSH ESI
006CF887 |. 52 |PUSH EDX
006CF888 |. C74424 2C 0000000>|MOV DWORD PTR [ESP+2C],0
006CF890 |. E8 ABB0F8FF |CALL Disciple.0065A940 ; <<<<<<<<<<<<,, + вышли отсюда и смотрим код вверху
006CF895 |. 83C4 14 |ADD ESP,14
006CF898 |. 84C0 |TEST AL,AL
006CF89A |. 74 33 |JE SHORT Disciple.006CF8CF
006CF89C |. 8B4424 18 |MOV EAX,DWORD PTR [ESP+18]
006CF8A0 |. 8B0D A078C301 |MOV ECX,DWORD PTR [1C378A0]
006CF8A6 |. 8B11 |MOV EDX,DWORD PTR [ECX]
006CF8A8 |. 6A 00 |PUSH 0
006CF8AA |. 8D2C40 |LEA EBP,DWORD PTR [EAX+EAX*2]
006CF8AD |. 8B4424 14 |MOV EAX,DWORD PTR [ESP+14]
006CF8B1 |. 8B6CA8 04 |MOV EBP,DWORD PTR [EAX+EBP*4+4]
006CF8B5 |. 8B80 E4000000 |MOV EAX,DWORD PTR [EAX+E4]
006CF8BB |. 6A 00 |PUSH 0
006CF8BD |. 55 |PUSH EBP
006CF8BE |. 56 |PUSH ESI
006CF8BF |. 50 |PUSH EAX
006CF8C0 |. 68 F8027F00 |PUSH Disciple.007F02F8 ; ASCII "GetResource"
006CF8C5 |. FF92 90020000 |CALL NEAR DWORD PTR [EDX+290]
006CF8CB |. 8B6C24 1C |MOV EBP,DWORD PTR [ESP+1C]
006CF8CF |> 8B4424 14 |MOV EAX,DWORD PTR [ESP+14]
006CF8D3 |. 45 |INC EBP
006CF8D4 |. 83C3 04 |ADD EBX,4
006CF8D7 |. 83C0 0C |ADD EAX,0C
006CF8DA |.^ E9 25FFFFFF \JMP Disciple.006CF804
006CF8DF |> 8B4C24 10 MOV ECX,DWORD PTR [ESP+10]
006CF8E3 |. 51 PUSH ECX
006CF8E4 |. 57 PUSH EDI ; Disciple.01C3FF80
006CF8E5 |. E8 B6FCFFFF CALL Disciple.006CF5A0
006CF8EA |. A1 A478C301 MOV EAX,DWORD PTR [1C378A4]
006CF8EF |. 8B90 E0000000 MOV EDX,DWORD PTR [EAX+E0]
006CF8F5 |. 8990 E4000000 MOV DWORD PTR [EAX+E4],EDX
006CF8FB |. 8B8F 78010000 MOV ECX,DWORD PTR [EDI+178]
006CF901 |. 8B97 7C010000 MOV EDX,DWORD PTR [EDI+17C]
006CF907 |. 8B07 MOV EAX,DWORD PTR [EDI] ; Disciple.007FA410
006CF909 |. 8BB7 70010000 MOV ESI,DWORD PTR [EDI+170]
006CF90F |. 8B9F 74010000 MOV EBX,DWORD PTR [EDI+174]
006CF915 |. 83C4 08 ADD ESP,8
006CF918 |. 51 PUSH ECX
006CF919 |. 52 PUSH EDX
006CF91A |. 8BCF MOV ECX,EDI ; Disciple.01C3FF80
006CF91C |. FF50 4C CALL NEAR DWORD PTR [EAX+4C]
006CF91F |. 8B07 MOV EAX,DWORD PTR [EDI] ; Disciple.007FA410
006CF921 |. 53 PUSH EBX
006CF922 |. 8BCF MOV ECX,EDI ; Disciple.01C3FF80
006CF924 |. 89B7 70010000 MOV DWORD PTR [EDI+170],ESI
006CF92A |. FF50 50 CALL NEAR DWORD PTR [EAX+50]
006CF92D |. E8 9E060000 CALL Disciple.006CFFD0
006CF932 |. E8 C9080000 CALL Disciple.006D0200
006CF937 |. 8B0D A478C301 MOV ECX,DWORD PTR [1C378A4]
006CF93D |. 85C9 TEST ECX,ECX
006CF93F |. 74 0F JE SHORT Disciple.006CF950
006CF941 |. 8B11 MOV EDX,DWORD PTR [ECX]
006CF943 |. 68 0000803F PUSH 3F800000
006CF948 |. 6A 06 PUSH 6
006CF94A |. FF92 BC040000 CALL NEAR DWORD PTR [EDX+4BC]
006CF950 |> 5E POP ESI ; 25F89E08
006CF951 |. 5B POP EBX ; 25F89E08
006CF952 |. 5F POP EDI ; 25F89E08
006CF953 |. B0 01 MOV AL,1
006CF955 |. 5D POP EBP ; 25F89E08
006CF956 |. 83C4 10 ADD ESP,10
006CF959 \. C3 RET006CF6D6 |. 896C24 08 MOV DWORD PTR [ESP+8],EBP
{
int v1; // ebp@1
int v2; // edi@1
char result; // al@2
signed int v4; // ecx@7
int v5; // ebx@7
unsigned int v6; // esi@7
int v7; // eax@9
int v8; // eax@13
int v9; // eax@15
int v10; // eax@16
signed int v11; // eax@18
signed int v12; // edx@20
int v13; // eax@25
signed int v14; // ebx@25
unsigned int v15; // ebp@25
unsigned int v16; // eax@26
int v17; // ecx@27
int v18; // eax@31
int v19; // eax@33
int v20; // eax@34
int v21; // eax@36
int v22; // esi@38
int v23; // eax@1
char v24; // zf@1
int v25; // eax@15
unsigned int v26; // edx@15
unsigned int v27; // ecx@26
int v28; // eax@33
unsigned int v29; // ecx@33
int v30; // esi@41
int v31; // ebx@41
int v32; // eax@41
int v33; // [sp+14h] [bp-10h]@1
int v34; // [sp+18h] [bp-Ch]@26
unsigned int v35; // [sp+20h] [bp-4h]@26
int v36; // [sp+1Ch] [bp-8h]@38
v2 = a1;
v23 = (*(int (**)(void))(*(_DWORD *)dword_1C378A4 + 0x34))();
v1 = v23;
v24 = *(_DWORD *)(dword_1C378A4 + 0xE4) == *(_DWORD *)(dword_1C378A4 + 0xE0); // ключевое место
v33 = v23;
if ( v24 )
{
(*(int (__stdcall **)(char *, char *, signed int, _DWORD))(*(_DWORD *)dword_1C378A4 + 0x258))(
"Msg_HLIngfo",
"Msg_SpellTooMuch",
1,
0);
(*(int (__stdcall **)(signed int, unsigned int))(*(_DWORD *)dword_1C378A4 + 0x4BC))(24, 0x3F800000u);
result = 0;
}
else
{
*(_DWORD *)(v2 + 372) >= *(_DWORD *)(v2 + 304);
if ( (unsigned __int8)sub_6CD850() )
{
result = 0;
}
else
{
v6 = *(_DWORD *)(v2 + 372);
v4 = 0;
v5 = v1 + 4;
while ( 1 )
{
if ( v6 >= *(_DWORD *)(v2 + 304) )
v7 = v2 + 316;
else
v7 = *(_DWORD *)(v2 + 0x12C) + 4 * v6;
if ( (unsigned int)v4 >= *(_DWORD *)(*(_DWORD *)v7 + 0x24) )
break;
if ( v6 >= *(_DWORD *)(v2 + 304) )
v8 = v2 + 316;
else
v8 = *(_DWORD *)(v2 + 0x12C) + 4 * v6;
v25 = *(_DWORD *)v8;
v26 = *(_DWORD *)(v25 + 0x24);
v9 = v25 + 32;
if ( v4 >= v26 )
v10 = v9 + 16;
else
v10 = *(_DWORD *)v9 + 4 * v4;
v11 = *(_DWORD *)v10;
if ( v4 == -1 || v4 >= 8 )
v12 = -1;
else
v12 = *(_DWORD *)v5;
if ( v12 < v11 )
{
(*(int (__stdcall **)(char *, char *, signed int, _DWORD))(*(_DWORD *)dword_1C378A4 + 600))(
"Msg_HLIngfo",
"Msg_NoRes",
1,
0);
(*(int (__stdcall **)(unsigned int, signed int))(*(_DWORD *)dword_1C378A4 + 0x4BC))(0x18u, 1065353216);
return 0;
}
++v4;
v5 += 12;
}
v13 = v33;
v15 = 0;
v14 = 0;
while ( 1 )
{
v27 = *(_DWORD *)(v2 + 304);
v34 = v13;
v16 = *(_DWORD *)(v2 + 372);
v35 = v15;
if ( v16 >= v27 )
v17 = v2 + 316;
else
v17 = *(_DWORD *)(v2 + 300) + 4 * v16;
if ( v15 >= *(_DWORD *)(*(_DWORD *)v17 + 36) )
break;
if ( v16 >= *(_DWORD *)(v2 + 304) )
v18 = v2 + 316;
else
v18 = *(_DWORD *)(v2 + 300) + 4 * v16;
v28 = *(_DWORD *)v18;
v29 = *(_DWORD *)(v28 + 36);
v19 = v28 + 32;
if ( v15 >= v29 )
v20 = v19 + 16;
else
v20 = v14 + *(_DWORD *)v19;
v21 = *(_DWORD *)v20;
if ( v14 != -4 )
{
if ( v14 <= 32 )
{
v22 = *(_DWORD *)v34;
v36 = 0;
if ( (unsigned __int8)SFChangeResourceNum(v33, v22, -v21, 0, &v36) )
{
(*(int (__stdcall **)(char *, _DWORD, int, _DWORD, _DWORD, _DWORD))(*(_DWORD *)dword_1C378A0 + 656))(
"GetResource",
*(_DWORD *)(v33 + 228),
v22,
*(_DWORD *)(v33 + 12 * v36 + 4),
0,
0);
v15 = v35;
}
}
}
++v15;
v14 += 4;
v13 = v34 + 12;
}
SFSpellStudent(v2, v33);
*(_DWORD *)(dword_1C378A4 + 228) = *(_DWORD *)(dword_1C378A4 + 224);
v30 = *(_DWORD *)(v2 + 368);
v31 = *(_DWORD *)(v2 + 372);
(*(int (__thiscall **)(int, _DWORD, _DWORD))(*(_DWORD *)v2 + 76))(
v2,
*(_DWORD *)(v2 + 380),
*(_DWORD *)(v2 + 376));
v32 = *(_DWORD *)v2;
*(_DWORD *)(v2 + 368) = v30;
(*(int (__thiscall **)(int, int))(v32 + 80))(v2, v31);
sub_6CFFD0();
sub_6D0200();
if ( dword_1C378A4 )
(*(int (__stdcall **)(signed int, unsigned int))(*(_DWORD *)dword_1C378A4 + 1212))(6, 0x3F800000u);
result = 1;
}
}
return result;
}char __usercall sub_6CF6B0<al>(int a1<eax>)
Cтавим бряк на запись маны и поднимаемся выше по коду, каждый раз ставя плюсики на уровень выхода из функции.
x1= [[1C378A4]+0xE4] – это значение устанавливается равным [[1C378A4]+0xE0] при изучении заклинания
x2= [[1C378A4]+0xE0] – количество игровых ходов, т.е. не игрока, а именно ходов игры.
Если x1 и x2 равны, то нельзя выучить заклинание.
x1 до начала самого первого хода в игре равно мусору. После изучения первого заклинания на пример на 5-ом ходу когда x2=5, то x1 становится равным 5. Делаем ход x2 становится равным 6, а x1 остаётся равным 3. Изучаем заклинание x1 становится равным 6.
Вывод: нельзя найти отсеиванием, т.к. врядли додумаешься до правил поиска )
Про то, как сделать пользование магией будет скоро в следующем посте. Надо делать почти также. Ставить бряк на Ману использовать заклинание и смотреть выше по коду…
Короче что просил Иван Иванови, то сделал.
Берём русскую версию CE.
\"Подсоединяем\" процесс игры
Идём в отладчик, нажимаем на Автоассемблер.
Пишем скрипт ниже.
Связываем, сохраняем таблицу. Активируем и играем.
//Бесконечное изучение заклинания
DisciplesIII.exe+2CF6DA:>E40000008BE83B91E0000000896C2408YYxxxxxxxx006A0168A8A47F0068FC
db eb 33
//Бесконечное использование заклинания
DisciplesIII.exe+27BFD7:>006A01508BCDFF92380600008B5C2418YYxxxxxxxx008B85E0000000898388
db 90 90 90 90 90 90
//Бесконечная постройка зданий
DisciplesIII.exe+2F35E3:>2418508BC78BCDE8xxxxxxxx85F67407YYxxxxxxxx00018B0Dxxxxxxxx85C9
db 90 90 90 90 90 90 90
[DISABLE]
DisciplesIII.exe+2CF6DA:>E40000008BE83B91E0000000896C2408YYxxxxxxxx006A0168A8A47F0068FC
db 75 33
DisciplesIII.exe+27BFD7:>006A01508BCDFF92380600008B5C2418YYxxxxxxxx908B85E0000000898388
inc [ebx+0000008c] //ff 83 8c 00 00 00
DisciplesIII.exe+2F35E3:>2418508BC78BCDE8xxxxxxxx85F67407YYxxxxxxxx90908B0Dxxxxxxxx85C9
mov byte ptr [esi+000000f0],01 //c6 86 f0 00 00 00 01[ENABLE]
Чит-код на \"Бесконечное использование заклинания\" было сложно найти ) SERGANT, я трейнер делать не буду, так что вся надежда по видимому только на тебя. Если есть вопросы, то я постараюсь помочь.
Ах да, по водову inc [ebx+0000008c]. Эти данные входят в структуру героя. Если кому надо те могут посмотреть рисунок выше и сравнить с этим указателем [[[[DisciplesIII.exe+18378A4]+00122b24]+1*4]+8c], он же и [ebx+0000008c], где ebx был рассчитан, а 8с = 0x22*4
-
Здесь вызывается не 0xDEADBEEF ("то что мы хотели"), а "0xDEADBEEF + dwLoadOffset".
А почему вычитается "0x400000" ?
-
Если игра в полноэкранном режиме, то эти кнопки не будут доступны. Так что ни одна дополнительная кнопка не позволит свернуть игру в окно.
-
Это зависит от конкретного случая.
Надо подразумевать простую схему. Когда используешь этот способ, то у тебя есть два адреса как минимум одного маршрута выполнения машинного кода. Первая точка это бряк на вводе от пользователя, вторая - бряк на адресе параметра, для которого нужно сделать чит. Соответсвенно, если есть проблемы с созданием чита, то нужно исследовать этот маршрут...
-
MasterGH, в старых версиях было специальное меню под это, где добавлялись функции в трейнер и вешались на них хоткеи. В 6.1 я такого не наблюдаю, либо это меню где-то спрятано...
В меню "Файл" есть опция генерации трейнера... Какие у тебя могли возникнуть трудности? очень странно
-
Akama, уже все давно узнали, что есть такая таблица ) И давно решили изучать её или нет...
Отлавливать функции нажатия клавиш надо для работы в отладке, чтобы определить как код игры реагирует на ввод пользователя. Если интересуют подробности, то их нужно искать в отладке...
-
Можно этим способом, а можно используя:
generateAPIHookScript(address, addresstojumpto, addresstogetnewcalladdress OPT)
-
В первый раз вижу такое меню. Хоть бы ссылку привёл этого видео.
D3DWindower помогает не всегда, у нас есть статьи по нему.
Возможно стоит поискать в Интернете способ установки оконного режима именно для какой-то игры. Если его нет, тогда лесть в отладку. По этому поводу у нас тоже есть статьи.
-
Мне туторы делать некогда
Подсказать не могу, т.к. для каждой игры свой случай.
Вот статья, там и видео про фильтры
-
Вот статья, там и видео.
-
Вот изменённый вариант:
Скрипт установки условного брейкпоинта на функции TranslateMessage.
В параметрах сравнения участвует код сообщения "UINT message"
Если сообщение равно сравниваемому, то отладчик прервётся и в поле лога выведет параметры структуры MSG
BOOL TranslateMessage(
const MSG* lpMsg // Указатель на структуру MSG, которая содержит информацию о сообщении извлеченную из очереди сообщений вызывающего потока при помощи использования функции GetMessage или PeekMessage.
);
typedef struct {
HWND hwnd; // Дескриптор окна, оконная процедура которого принимает сообщение.
UINT message; // Определяет код сообщения. Приложения могут использовать только младшее слово; старшее слово зарезервировано системой.
WPARAM wParam; // Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
LPARAM lParam; // Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
DWORD time; // Определяет время, в которое сообщение было помещено в очередь.
POINT pt; // Устанавливает позицию курсора, в экранных координатах, в момент, когда сообщение было помещено в очередь.
} MSG, *PMSG;
Пример использования.
Пример1. Установка условного брейкпоинта функции TranslateMessage в сравнении с параметром MSG:
-- Сработает когда пользователь отпустит левую кнопку мышки
WM_LBUTTONUP = 0x202 (другие коды сообщени ищите в Интернете)
StartDebug_TranslateMessageCondition_onMSG(WM_LBUTTONUP)
Пример2. Установика безусловного брейкпоинта с логировнием всех сообщений:
StartDebug_TranslateMessage()
Пример3. Если необходимо только прерваться на некоторой функции без сбора параметров:
StartDebugSomeFunction(functionName)
Пример4. Если необоходимо остановить отладку, то вызывать:
StopDebug()
]]--
local mode = 0
local addressesBreakPoint = {}
local countAddressesBreakPoint = 0
function AddBreakPointExecut(addressFunction)
countAddressesBreakPoint = table.getn(addressesBreakPoint)
countAddressesBreakPoint = countAddressesBreakPoint + 1
addressesBreakPoint[countAddressesBreakPoint] = addressFunction
debug_setBreakpoint(addressFunction, 1, bptExecute)
end
function DeleteAllBreakPoint()
for i=1, countAddressesBreakPoint do
debug_removeBreakpoint(addressesBreakPoint[i])
end
countAddressesBreakPoint = 0
end
-- Единая функция обработки сообщений о прерывании
function debugger_onBreakpoint()
local withIn = false
for i=1, countAddressesBreakPoint do
if (EIP == addressesBreakPoint[i]) then
withIn = true
break
end
end
if (not withIn) then
return 1
end
if ( (mode == 1) or (mode == 2) ) then
local pMSG = readInteger(ESP+0x4)
local MSG = readInteger(pMSG+0x4)
if ((mode == 1) and (MSG ~= _iMSGBreak)) then
return 1
end
local s = string.format(" • Call to %s from \"%s\" •\n\r\n>> hWnd = %X\n\r\n>> MSG = %X\n\r\n>> wParam = %X\n\r\n>> lParam = %08X\n\r\n>> Time = %X\n\r\n>> Point = %i x %i\n\r\n", getNameFromAddress(EIP), getNameFromAddress(readInteger(ESP)),
readInteger(pMSG),
MSG,
readInteger(pMSG+0x8),
readInteger(pMSG+0xC),
readInteger(pMSG+0x10),
readInteger(pMSG+0x14), readInteger(pMSG+0x18))
if (mode == 1) then -- WM_LBUTTONUP
print(s) -- записываем в лог LuaEngine текст из loglist
return 0 -- ставим бряк
else -- в случае если условие не выполнено
print(s) -- записываем в лог LuaEngine текст из loglist при не выполненом условии
return 1 -- продолжаем без бряка
end
end
return 0
end
function StartDebug_TranslateMessageCondition_onMSG(iMSGBreak)
DeleteAllBreakPoint()
mode = 1
_iMSGBreak = iMSGBreak
local addressFunction = getAddress("TranslateMessage")
AddBreakPointExecut(addressFunction)
print(string.format("Включен режим остановки на фунции TranslateMessage с условием: MSGBreak == %X",iMSGBreak))
end
function StartDebug_TranslateMessage()
DeleteAllBreakPoint()
mode = 2
local addressFunction = getAddress("TranslateMessage")
AddBreakPointExecut(addressFunction)
print("Включен режим остановки на фунции TranslateMessage без условий")
end
function StartDebugSomeFunction(functionName)
mode = 0
local addressFunction = getAddress(functionName)
AddBreakPointExecut(addressFunction)
end
function StopDebug()
DeleteAllBreakPoint()
_iMSGBreak = 0
end--[[
Я запустил функцию StartDebug_TranslateMessage() и StopDebug(), а остальные не запускал и поэтому могут быть ошибки, которых я не заметил.
Если будет время сделаю форму с кнопками, полями ввода и т.п., а то через консоль неудобно.
-
Кое-что не совсем правильно. И немного не удобно в том, что нет выбора между остановкой просто на функции и остановкой по равенству кода сообщения... я потом поправлю, сейчас нет времени.
И на будущее createStringlist() в твоём случае постоянно создаёт новый и новый список. Старый при этом не разрушается и происходит "утечка памяти". Достаточно создать список только один раз. Также лучше пользоваться просто print() я что-то "перенасоветовал". Когда я советовал я забыл, что ты ведёшь логи с остановками в Отладчике для пользователя. В этом случае проще использовать print() c длинной строкой (через string.fortmat)... Ладно, как уже писал, позже поправлю.
-
Актуально:
local Function = getAddress("TranslateMessage")
Для лучшей производительности лучше:
1) cтроку:
local Condition = 0x202 -- MSG==202 //WM_LBUTTONUP
вынести из function debugger_onBreakpoint().
2) строку :
if (EIP == Function) then
заменить на:
if (EIP ~= Function) then
return 1
end3) Возможно лучше использовать объект от Stringlist вместо множественного построчного print(). Метод "strings_getText( твой Stringlist )" может сразу возвратить большую строку лога, которую уже можно обработать через print
Также помимо кодов сообщений можно логировать и адрес возврата по [esp+0]. А также другую информацию:
BOOL TranslateMessage(
const MSG* lpMsg // Указатель на структуру MSG, которая содержит информацию о сообщении извлеченную из очереди сообщений вызывающего потока при помощи использования функции GetMessage или PeekMessage.
);
typedef struct {
HWND hwnd; // Дескриптор окна, оконная процедура которого принимает сообщение.
UINT message; // Определяет код сообщения. Приложения могут использовать только младшее слово; старшее слово зарезервировано системой.
WPARAM wParam; // Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
LPARAM lParam; // Определяет дополнительную информацию о сообщении. Точное значение зависит от значения члена структуры message.
DWORD time; // Определяет время, в которое сообщение было помещено в очередь.
POINT pt; // Устанавливает позицию курсора, в экранных координатах, в момент, когда сообщение было помещено в очередь.
} MSG, *PMSG; -
Ссылка на тему человека Recifense, там же есть файл .CT таблицы.
В [pGold] есть запись, посмотри внимательно. А вот в [iPlayerID] записи нет, потому что это просто переменная для чтения. В этой переменной идентификатор игрока, он всегда равен единице.
По поводу того, что Recifense лучше меня... Скорее всего так и есть, т.к. у него большой опыт в нахождении связей между указателями. Скорее всего, он не работает с декомпиляторами. Это только я так заморачиваюсь. Метод у него, скорее всего, такой. Если он не может сделать один чит, то он делает другой и ищет связи между поинтерами в структурах сделанных читов. Т.е. в его случае из Dessect Data окна он не вылазит вообще и наверняка активно пользуется сканером памяти в поиске адресов и указателей в структурах... так же, скорее всего, он часто ставит бряки на адреса указателей. Указатели эти расположены в структурах, где они характерны только для данной структуры. Мне надо было обратить внимание на смещение +0x44 в структуре "Передвижения" и искать связь этого указателя со структурой где расположен адрес золота моего героя. Ведь и адрес золота, и адрес очков хождения должны обязательно принадлежать герою за которого я играю.
Таблица Recifense показала, что надо думать головой в направлении принадлежности адресов к структурам, которые каким-то образом связаны между собой. Т.е. если мы не можем идентифицировать принадлежность адреса очков ходов к герою за которого играем, то надо найти через бряк структуру этого адреса очков ходов и, например, структуру адреса золота и попытаться найти связи между этим структурами...
По поводу этой игры. Подобная сложность создания читов почти всегда характерна для похожих игр, где много юнитов
-
Тебе нужно знать программирование под Windows.
Нужно знать как работать с WinApi функиями чтения, записи в память. Через чтение можно осуществлять чтение цепочек указателей.
Нужно знать как изменить блок защиты памяти с защиты чтения на защиту записи, чтобы писать в него без исключений...
Нужно знать работу с поиском dll-ок и принадлежности их к процессам.
Нужно знать как сделать поиск процесса по названию его окна или по имени процесса, подключение к процессу. Нужно знать где закрывать дескрипторы. Нужно знать работу с обработкой сообщений чек боксов.
Если будешь писать на C++, то нужно знать как создавать окно и привязывать функцию к этому окну.
Тебе оно надо?
Это ещё не все. Тебе надо будет самостоятельно искать примеры или самому написать "правильный инжект в выделенную память".
Туторы по CE Autoassembler Engine
in Cheat Engine
Опубликовано
Не одно и тоже. Способ который я привёл рассчитывает указатель каждый раз заново, а твой - только при активации чита. Применять тот или иной способ зависит от кода игры. Посмотри в дизассемблере что у тебя получается при активации чита. Так же советую это делать почаще для версии CE 6.1, т.к. она может неправильно ассемблировать.
По поводу вылета на "faddp dword [ecx]". У меня вообще эта инструкция не ассемблировалась. Похоже она работает только с регистрами FPU.