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

Не могу понять операции над float значениями.


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

В общем сижу ломаю голову, над тем как взломать апгрейды соперников в nfs most wanted (2005).

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

Во время загрузки, дальше из этих уровней (по 4 байта, которые лежат в стеке) вычисляются другие значения (float, не больше 1 и не меньше 0).

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

Вот запутался в этом коде:

speed.exe+277D11  - fld dword ptr [esp+00000088]
speed.exe+277D18 - fcomp dword ptr [speed.exe+49096C] { [1.00] }
speed.exe+277D1E - mov [esp+78],00000000 { 0 }
speed.exe+277D26 - fnstsw ax
speed.exe+277D28 - test ah,01 { 1 }

speed.exe+277D28 - test ah,01 { 1 }
speed.exe+277D2B - jne speed.exe+277D51
speed.exe+277D2D - mov eax,[esp+00000084]

Текущее значение (float) лежит в [esp+88].

Если провести инъекцию по замене текущего значения перед адресом speed.exe+27D11, апгрейды машин меняются.

Если провести после speed.exe+277D1E, апгрейды не меняются. Причем в стек ничего не добавляется, как показывается в Tracer cheatengine.

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

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

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

2 часа назад, DeadShot сказал:

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

ты же сам ответил:

2 часа назад, DeadShot сказал:

Если провести инъекцию по замене текущего значения перед адресом speed.exe+27D11, апгрейды машин меняются.

mov dword ptr [esp+00000088],(float)1
fld dword ptr [esp+00000088]

ЗЫ: И кстати. если занопить прыжок:

speed.exe+277D2B - jne speed.exe+277D51

например вот таким образом:

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

[ENABLE]
speed.exe+277D2B:
db 90 90 90 90 90 90  // только нужно проверить кол-во байт
 
[DISABLE]
speed.exe+277D2B:
jne speed.exe+277D51  // только нужно проверить кол-во байт

 

то это тоже думаю приведёт к тому же результату.

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

Garik66, как я полагаю, это общее значение, поэтому менять в этом месте не нужно.

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

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

jne speed.exe+277D51

Если занопить все равно ничего не изменится. хоть с nop, хоть с je, хоть jmp.

Дальше идет еще одна такая проверка, на этот раз на 0.01.


 

speed.exe+277D51 - fld dword ptr [esp+00000088]
speed.exe+277D58 - fcomp dword ptr [speed.exe+490968] { [0.01] }
speed.exe+277D5E - fnstsw ax
speed.exe+277D60 - test ah,41 { 65 }
speed.exe+277D63 - jne speed.exe+277F68

 

Если у машины средние апгрейды (0.0 < x < 1.0) продолжается такой код:

speed.exe+277D69 - push esi
speed.exe+277D6A - mov ecx,ebx
speed.exe+277D6C - call speed.exe+5A840
speed.exe+277D71 - push 00 { 0 }
speed.exe+277D73 - push 00 { 0 }
speed.exe+277D75 - push speed.exe+4A9A64 { ["part_upgrade"] }
speed.exe+277D7A - mov ecx,ebx
speed.exe+277D7C - call speed.exe+56D40

но если поставить среднее значение в стеке перед этими проверками (0.5, например) и дойдя сюда speed.exe+277D6A поменять значение в стеке на 0.0 или 1.0, эффекта никакого не будет, все так же останется как и было до этих кодов (0.5, например).

fld dword ptr [esp+00000088]
fcomp dword ptr [speed.exe+490968] { [0.01] }
fnstsw ax 
jne speed.exe+277F68



Dison, Нет никакого скрипта, т.к. с брейкпоинтом игра вылетит, а при подключение узнать что читает этот адрес появляются, куча инструкций, это не обычный адрес в памяти, это адрес в стеке, даже любой push или pop, add/sub esp, x,  будет как доступ.

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

Dino, в st(0) и st(1)? пробовал после  fnstsw ax выталкивать данные и загружать fldz, fld1, эффекта нет.

fnstsw ax, меняет значение регистра eax, как, каким образом?

 

Что за магический код такой? как узнать откуда дальше берутся значения, и какие значения.

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

14 часа назад, DeadShot сказал:

Garik66, как я полагаю, это общее значение, поэтому менять в этом месте не нужно.

Нужно либо фильтровать на этой инструкции, если тебя интересует конкретная машина, либо смотреть выше по коду, откуда берется в esp - начало структуры машины.

 

14 часа назад, DeadShot сказал:

в st(0) и st(1)? пробовал после  fnstsw ax выталкивать данные и загружать fldz, fld1, эффекта нет.

После  fnstsw ax смысла уже нет что-то переписывать.

14 часа назад, DeadShot сказал:

fnstsw ax, меняет значение регистра eax, как, каким образом?

опкод  fnstsw ax, копирует значение из st(0) в память, либо в регистр ax, в твоём случае именно в ax. // не верно - смотри ниже.

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

1 час назад, Garik66 сказал:

Нужно либо фильтровать на этой инструкции, если тебя интересует конкретная машина, либо смотреть выше по коду, откуда берется в esp - начало структуры машины.

 

После  fnstsw ax смысла уже нет что-то переписывать.

опкод  fnstsw ax, копирует значение из st(0) в память, либо в регистр ax, в твоём случае именно в ax. 

ну не путай человека, пускай вон лучше справку почитает. fnstsw ничего не копирует из st(0)

 

14 часа назад, DeadShot сказал:


Dino, в st(0) и st(1)? пробовал после  fnstsw ax выталкивать данные и загружать fldz, fld1, эффекта нет.

fnstsw ax, меняет значение регистра eax, как, каким образом?

 

Что за магический код такой? как узнать откуда дальше берутся значения, и какие значения.

чего ты хочешь добиться командами fldz, fld1? Чтобы вытолкнуть из st(0) существует команда fstp

 

никакой магии, элементарное не знание основ.

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

2 минуты назад, Dino сказал:

ну не путай человека, пускай вон лучше справку почитает. fnstsw ничего не копирует из st(0)

Может я не так понял?

вот что написано:

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

 Команды fstsw и fnstsw сохраняют текущее значение слова статуса FPU в указанном месте. Операндом-адресатом может быть либо 16 бит в памяти, либо регистр AX. fstsw перед сохранением слова проверяет на подвешенные немаскируемые прерывания, fnstsw этого не делает.
   Команды fstcw и fnstcw сохраняют текущее значение управляющего слова FPU в указанном месте в памяти. fstcw перед сохранением слова проверяет на подвешенные немаскируемые прерывания, fnstcw этого не делает. fldcw загружает операнд в управляющее слово FPU. Операндом должно быть 16-битное расположение в памяти.

 

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

11 минуту назад, Garik66 сказал:

Может я не так понял?

вот что написано:

  Скрыть содержимое

 Команды fstsw и fnstsw сохраняют текущее значение слова статуса FPU в указанном месте. Операндом-адресатом может быть либо 16 бит в памяти, либо регистр AX. fstsw перед сохранением слова проверяет на подвешенные немаскируемые прерывания, fnstsw этого не делает.
   Команды fstcw и fnstcw сохраняют текущее значение управляющего слова FPU в указанном месте в памяти. fstcw перед сохранением слова проверяет на подвешенные немаскируемые прерывания, fnstcw этого не делает. fldcw загружает операнд в управляющее слово FPU. Операндом должно быть 16-битное расположение в памяти.

 

 

под "текущее значение слова статуса FPU" подразумевается регистр состояния SR. Ну сам логически порассуждай, как можно число с плавающей точкой в 16 бит уместить :D 

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

1 минуту назад, Dino сказал:

 

под "текущее значение слова статуса FPU" подразумевается регистр состояния SR. Ну сам логически порассуждай, как можно число с плавающей точкой в 16 бит уместить :D 

Ну да в два байта не всунем. :wacko: - ну застыдил.

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

17 час назад, DeadShot сказал:

Если занопить все равно ничего не изменится. хоть с nop, хоть с je, хоть jmp.

Дальше идет еще одна такая проверка, на этот раз на 0.01.

Если правильно занопить

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

[ENABLE]
speed.exe+277D2B:
	nop
	nop

[DISABLE]
speed.exe+277D2B:
	jne speed.exe+277D51

 

, то код на следующую проверку никогда не попадёт.

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

speed.exe+277CE0 - push -01 { 255 }
speed.exe+277CE2 - push speed.exe+47AB30 { [8DE090B8] }
speed.exe+277CE7 - mov eax,fs:[00000000] { 0 }
speed.exe+277CED - push eax
speed.exe+277CEE - mov fs:[00000000],esp { 0 }
speed.exe+277CF5 - sub esp,68 { 104 }
speed.exe+277CF8 - push ebx
speed.exe+277CF9 - push esi
speed.exe+277CFA - mov esi,[esp+00000080]
speed.exe+277D01 - push 00 { 0 }
speed.exe+277D03 - push 00 { 0 }
speed.exe+277D05 - mov ebx,ecx
speed.exe+277D07 - push esi
speed.exe+277D08 - mov [esp+14],ebx
speed.exe+277D0C - call speed.exe+56CB0
speed.exe+277D11 - fld dword ptr [esp+00000088]
speed.exe+277D18 - fcomp dword ptr [speed.exe+49096C] { [1.00] }
speed.exe+277D1E - mov [esp+78],00000000 { 0 }
speed.exe+277D26 - fnstsw ax
speed.exe+277D28 - test ah,01 { 1 }
speed.exe+277D2B - nop                         // ноп прыжка
speed.exe+277D2C - nop                         // ноп прыжка
speed.exe+277D2D - mov eax,[esp+00000084]
speed.exe+277D34 - push eax
speed.exe+277D35 - mov ecx,ebx
speed.exe+277D37 - call speed.exe+5A840
speed.exe+277D3C - pop esi
speed.exe+277D3D - mov eax,ebx
speed.exe+277D3F - pop ebx
speed.exe+277D40 - mov ecx,[esp+68]
speed.exe+277D44 - mov fs:[00000000],ecx { 0 }
speed.exe+277D4B - add esp,74 { 116 }
speed.exe+277D4E - ret 000C { 12 }
speed.exe+277D51 - fld dword ptr [esp+00000088] // сюда уже не попадём.

 

 

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

Снова не то, кроме с "fnstsw ax загружает регистр состояния sr или swr в ax, долго ломал голову как fnstsw  может загрузить float значение в ax.

На счет fld1, fldz и инструкций выталкивания fstp, я так и делал, выгружал с помощью fstp [_temp] 2 раза, а дальше уже был тест с комбинациями загрузок 0.00 и 1, с помощью fldz и fld1.

На счет снова " Если правильно занопить", в данном случае не нужно ничего нопить, и фильтровать на этом месте никак не получится. т.к. этот код выполнится только по одному разу для апгрейдов ОДНОЙ машины. (как я уже писал, полагаю что создается общий шаблон для создания машин, из которого через хрен знает через сколько инструкций создаются все 4 машины, следствием которого является одинаковые характеристики по мощности, либо другой вариант, машины создаются произвольно, но в процессе езды будут выдергиваться данные из этого шаблона, как множители например к стандартным характеристикам машин).

+ Это значение используется для вычисления другого значения походу, поставил значение 0.23 в [esp+88], дальше в процессе гонки изменил значение адресов содержащие 0.23 на 1 и на 0, эффекта не получил.

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

15 час назад, DeadShot сказал:

Снова не то, кроме с "fnstsw ax загружает регистр состояния sr или swr в ax, долго ломал голову как fnstsw  может загрузить float значение в ax.

На счет fld1, fldz и инструкций выталкивания fstp, я так и делал, выгружал с помощью fstp [_temp] 2 раза, а дальше уже был тест с комбинациями загрузок 0.00 и 1, с помощью fldz и fld1.

ты код то покажешь?

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

Нет, готового кода, постоянно удаляю что не работает (не нужное). Тот участок описывает примерно вот такую логику, а вся запарка с fnstsw ax, просто счетчик:

// upgrade_percent = значению в стеке.
if(upgrade_percent == 1.0)
{
  //далее работаем с формулами для максимального апгрейда, 
  //поэтому замена значения upgrade_percent не вызывает никакого эффекта. 
  return;
} else if(upgrade_percent == 0.0)
{
  //далее работаем с формулами для апгрейда равного 0,
  //поэтому замена значения upgrade_percent не вызывает никакого эффекта. 
  return;
}
// если процент апгрейдов средний работаем с формулами для среднего апгрейда, 
// который будет использовать значение которое лежит на upgrade_percent.
// и который должен соответствовать условию 0 < upgrade_percent < 1. 
// смысл условия в том что походу в некоторых формулах 0 и 1 могут дать одинаковый результат.
// а в случае с апгрейдом машин 0 и 1 должны давать разный результат

Используя такую инъекцию, обхожу проверку условий (т.к. машина у меня имеет макс.апгрейды), чтоб дойти до требуемой стандартной формулы:

[ENABLE]
"speed.exe"+277D11:
  jmp speed.exe+277D69
  nop
  nop

[DISABLE]
"speed.exe"+277D11:
   fld dword ptr [esp+00000088]
//Alt: db D9 84 24 88 00 00 00

Дальше ставить трейсер на эту точку (ставя перед условиями проверки, попадем сюда тока после овер миллион инструкций, на что не хватит либо оперативки либо нервов на ожидание):

speed.exe+277EDD - mov eax,[esp+00000090]  // Достаем из стека процент апгрейда 
speed.exe+277EE4 - lea edx,[esp+40]
speed.exe+277EE8 - push edx
speed.exe+277EE9 - push eax  // Обратно кладем в стек (процент апгрейда будет иметь другой адрес)
speed.exe+277EEA - push esi
speed.exe+277EEB - lea ecx,[esp+3C]
speed.exe+277EEF - push ecx
speed.exe+277EF0 - lea edx,[esp+30]
speed.exe+277EF4 - push edx
speed.exe+277EF5 - call speed.exe+276280 // Вызов формулы

Ну и код самой формулы и куда кладется результат:

speed.exe+2762DA - fld dword ptr [speed.exe+49096C] { [1.00] }
speed.exe+2762E0 - mov ecx,[esp+20]
speed.exe+2762E4 - fsub dword ptr [esp+1C] // процент апгрейда
speed.exe+2762E8 - mov eax,[ecx+0C]
speed.exe+2762EB - test eax,eax
speed.exe+2762ED - fmul dword ptr [esp+04]
speed.exe+2762F1 - fld dword ptr [esp+08]
speed.exe+2762F5 - fmul dword ptr [esp+1C] // процент апгрейда
speed.exe+2762F9 - faddp 
speed.exe+2762FB - fstp dword ptr [esp+1C]
...
speed.exe+276311 - mov edx,[esp+1C]
speed.exe+276315 - mov [eax],edx

При загрузке, к инструкции speed+276315 получают доступ 72 адреса, может и больше.  Теперь уже можно подумывать написать фильтр. Если кто тоже хочет покопаться в поиске фильтра "моя/не моя тачка", началось всё отсюда:

speed.exe+2F4A07 - mov esi,eax // тут должен лежать адрес структуры (или чего там) текущей машины
                               // апгрейды в 4 байтом значении (0 - нет апгрейда, 1-4 - уровни апгрейдов)
                               // начиная с [esi/eax+78] вроде
speed.exe+2F4A16 - repe movsd 
speed.exe+2F4A09 - mov ecx,00000066 { 102 }
speed.exe+2F4A0E - lea edi,[esp+78]
speed.exe+2F4A12 - lea eax,[esp+78] 
speed.exe+2F4A18 - mov [esp+70],eax

А тут уже вычисляется float значение, которую называл процентом апгрейда:

speed.exe+278B40 - fild dword ptr [esp+3C]
speed.exe+278B44 - lea edx,[esp+10]
speed.exe+278B48 - fidiv dword ptr [esp+0C]
speed.exe+278B4C - fstp dword ptr [esp+3C]

 

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

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

define(address,"speed.exe"+277D11)
define(bytes,D9 84 24 88 00 00 00)

[ENABLE]

assert(address,bytes)
alloc(newmem,$1000)

label(code)
label(point)
label(return)

newmem:
point:
  cmp esp,0019F618
  je code

  mov dword ptr [esp+88],(float)0

code:
  fld dword ptr [esp+00000088]
  jmp return

address:
  jmp newmem
  nop
  nop
return:

[DISABLE]

address:
  db bytes
  // fld dword ptr [esp+00000088]

dealloc(newmem)

там где cmp esp,0019F618 - 0019F618 это верхушка стека, дело в том, что на этом месте "speed.exe"+277D11-fld dword ptr [esp+00000088] получают доступ два разных адреса стека, первый адрес 7 раз, второй адрес 21 раз, получается такое соотношение. 1 (игрок) * 7 (видов апгрейда) : 3 (соперники) * 7 (видов апгрейда)) = 7:21.
(и чего не проверил это 2 дня назад.)

Спасибо за подсказки с fnstsw ax .

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

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

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

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