Автор Тема: Вопросы по замене ассемблерных инструкций в asi.  (Прочитано 5660 раз)

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +2/-0
  • Its cool! Man
    • Просмотр профиля
У меня подозрения, что она используется за слежением наполненности какого-то глобального массива вершин. То есть на определенном этапе рендера счетчик обнуляется и в массив набиваются вершины каких-то объектов, они рендерятся и счетчик снова обнуляется. То, что я выводил его в лог по таймеру, похоже происходило вне этих функций. Не знаю, в документации к RW упоминается о каком-то кэшировании геометрии. Походу это типа кэша. Сегодня попробую вывести логи.

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 512
  • Репутация: +33/-0
    • Просмотр профиля
Код: ASM
  1. .text:005BD7AC 0E0 81 3D 74 5F 9B 00 FC 01 00 00                 cmp     ds:dword_9B5F74, 1FCh
  2. .text:005BD7B6 0E0 7C 57                                         jl      short loc_5BD80F

Вот тут идет процесс сравнения этой переменной с не маленьким значением.
« Последнее редактирование: Декабрь 02, 2013, 11:54:11 pm от Sektor »

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +2/-0
  • Its cool! Man
    • Просмотр профиля
Код: ASM
  1. .text:005BD7AC 0E0 81 3D 74 5F 9B 00 FC 01 00 00                 cmp     ds:dword_9B5F74, 1FCh
  2. .text:005BD7B6 0E0 7C 57                                         jl      short loc_5BD80F

Вот тут идет процесс сравнения этой переменной с не маленьким значением.
508 - это немного, походу общий буфер для каких-то мелких объектов. На выходных надо разобраться с "immediate mode" RW, чтобы лучше понять.
« Последнее редактирование: Декабрь 02, 2013, 11:54:27 pm от Sektor »

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +2/-0
  • Its cool! Man
    • Просмотр профиля
Не получилось, игра вылетает. Похоже, что нужно взять всю функцию, поместить в свой плагин, джампить на ее копию в плагине и уже в копии в плагине что-то посылать на лог.

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 512
  • Репутация: +33/-0
    • Просмотр профиля
Цитировать
Не получилось, игра вылетает.
С какой ошибкой вылетела? Там кажись адрес должен быть показан в MessageBox.

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +2/-0
  • Its cool! Man
    • Просмотр профиля
С какой ошибкой вылетела? Там кажись адрес должен быть показан в MessageBox.
Я разные варианты пробовал, разные адреса были, в том числе и адреса возврата. Вообщем, я считаю этот метод слишком трудоемким. Проще всю функцию перенести в плагин, а в экзешнике поставить джамп на нее, а в коде плагина уже править ее как надо.

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 512
  • Репутация: +33/-0
    • Просмотр профиля
Цитировать
Вообщем, я считаю этот метод слишком трудоемким.
Я ранее говорил, что этот метод не эффективный. Обычно этот метод используют, для не больших правок и то в нашем случае, оно не нужно. В дальнейшем к моддингу не подлежит, все это дело. Дело в том что когда есть переписанные функции, мы быстро можем в них что-то добавить свое, изменить да что угодно сделать на C++. При этом не упереться на ассемблерные инструкции, а разрабатывать плагины на языке высокого уровня. Кода естественно будет не мало, вот по этому все нужно переписывать так, что-бы оно было в соответствующих модулях.  Это 10-тками статьями не рассказать, нужно гораздо больше написать и также я планировал сделать как практические статьи, где какой-то мод на плагине мы будем делать своими руками, пошагово.

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +2/-0
  • Its cool! Man
    • Просмотр профиля
Начал было sub_5C1710 переписывать на c++. Компилятор ругался, пока я не исправил DWORD sub_5C1710 = на void* sub_5C1710 =, а лучше выполнять приведение адреса прямо в месте вызова, а то компилятор ругается матом постоянно.
Короче облом в том, что там есть структура CCamera и не известно смещения ее полей, а в коде функции идет многоуровневое обращение к полю сначала CCamera, потом к полям ее полей  - до 4-х уровней.
Еще не понятно, что такое UNDEF(число). Так что тоже не простой метод.
Короче надо копаться сразу во всем коде, искать взаимосвязи, намеки на тип, искать среди аргументоы уже исследованных функций.
Кстати в Code:Blocks есть такая возможность в подсветке синтаксиса. Когда выделяешь переменную в одном месте, она выделяется во всем коде - удобно. Не знаю, есть ли это в MSVC.
« Последнее редактирование: Ноябрь 29, 2013, 07:56:45 am от graveman »

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 512
  • Репутация: +33/-0
    • Просмотр профиля
Код: ASM
  1. .text:005C1710         sub_5C1710      proc near  

Это статичный метод камеры.

Кстати:

Код: ASM
  1. .text:005C1750                                   loc_5C1750:                             ; CODE XREF: sub_5C1710+2Dj
  2. .text:005C1750 0C0 B9 98 46 7E 00                                mov     ecx, offset _camera.__parent.matrix.__parent.top
  3. .text:005C1755 0C0 D9 41 08                                      fld     dword ptr [ecx+8]
  4. .text:005C1758 0C0 D8 1D 78 CD 69 00                             fcomp   flt_69CD78
  5. .text:005C175E 0C0 DF E0                                         fnstsw  ax
  6. .text:005C1760 0C0 F6 C4 45                                      test    ah, 45h
  7. .text:005C1763 0C0 0F 85 82 00 00 00                             jnz     loc_5C17EB
  8. .text:005C1769 0C0 D9 41 04                                      fld     dword ptr [ecx+4]

Исправь вот эти вещи:

fld     dword ptr [ecx+8]
dword ptr [ecx+4]


Выделив их и нажав, на клавишу "T" найди структуру RwV3d. Должно получится так:

Код: ASM
  1. .text:005C1750 0C0 B9 98 46 7E 00                                mov     ecx, offset _camera.__parent.matrix.__parent.top
  2. .text:005C1755 0C0 D9 41 08                                      fld     [ecx+RwV3d.z]
  3. .text:005C1758 0C0 D8 1D 78 CD 69 00                             fcomp   flt_69CD78
  4. .text:005C175E 0C0 DF E0                                         fnstsw  ax
  5. .text:005C1760 0C0 F6 C4 45                                      test    ah, 45h
  6. .text:005C1763 0C0 0F 85 82 00 00 00                             jnz     loc_5C17EB
  7. .text:005C1769 0C0 D9 41 04                                      fld     [ecx+RwV3d.y]

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

Код: ASM
  1. .bss:007E4688 ?? ?? ?? ?? ?? ?? ?? ?? ?? ??+    _camera         CCamera <?>  

Достаточно переписать структуры камеры в один .h файл, и сделать подхват переменной

в данном случае так:

Код: C++
  1. auto pCamera  = (CCamera*)0x07E4688;

ну и в принципе все, она наша, мы можем потом делать? что угодно с ее полями, через переменную pCamera.

Структуру камеры можно взять в этом посте в vcCamera.h

Но на самом деле CCamera - это класс, но пока можно использовать как обычную структуру. Просто нужно переписывать ее методы, для того что-бы получился полноценный класс камеры.
« Последнее редактирование: Декабрь 02, 2013, 11:58:00 pm от Sektor »

Оффлайн graveman

  • Прохожий
  • *
  • Сообщений: 50
  • Репутация: +2/-0
  • Its cool! Man
    • Просмотр профиля
Очень полезная информация, Sector.
Начал разбирать эту функцию. Это
RwV3d field_8B8;
RwV3d field_8C4;
RwV3d field_8D0;
RwV3d field_8DC;
возможно нормали плоскостей пирамиды видимости камеры.

Sector, не знаешь, как найти смещение метода класса в классе?
« Последнее редактирование: Декабрь 02, 2013, 11:48:13 am от Sektor »

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 512
  • Репутация: +33/-0
    • Просмотр профиля
Цитировать
Sector, не знаешь, как найти смещение метода класса в классе?

Обычные методы, не какой роли к полям не играют за исключением виртуальных методов. Обычные методы, могут сами по себе лежать где угодно в коде. Работает также как функция, только перед вызовом помещается указатель на объект класса в ecx.

Цитировать
Начал разбирать эту функцию. Это
RwV3d field_8B8;
RwV3d field_8C4;
RwV3d field_8D0;
RwV3d field_8DC;

Еще одно пояснение. Это не функции, это обычные структурные поля.

Код: C++
  1. struct RwV3d{
  2.   float x;
  3.   float y;
  4.   float z;
  5. };


« Последнее редактирование: Декабрь 02, 2013, 11:57:30 pm от Sektor »

Оффлайн xanser

  • Главный Модератор
  • Опытный
  • *****
  • Сообщений: 498
  • Репутация: +43/-0
  • Есть такая профессия - на работе сидеть
    • Просмотр профиля
А у меня вопрос по замене ассемблерного кода ассемблерным. Хочу заменить первый кусок кода на второй. Сначала я делал в лоб, писал команды подряд, после них все занупил. Программа вылетела на нулевом адресе 0x000000, не знаю что это такое, я так понял мой код не понравился, хотя я сто раз его проверил и уверен в правильности. Тогда я сделал то же самое, но распределил команды по строкам так, чтобы сохранить количество байтов в строках, т.е. меняю 5 байтов на 5, 2 на 2 и т.д., между ними занупил и все заработало. Вопрос - нужно ли сохранять эту построчную структуру байтов или можно писать любые команды подряд и они правильно поймутся?

Оригинал:

Код: ASM
  1. .text:00601A52 50                                            push    eax             ; phkResult
  2. .text:00601A53 68 19 00 02 00                                push    20019h          ; samDesired
  3. .text:00601A58 6A 00                                         push    0               ; ulOptions
  4. .text:00601A5A 68 88 63 6D 00                                push    offset SubKey   ; "Software\\Microsoft\\Windows\\CurrentVersi"...
  5. .text:00601A5F 68 01 00 00 80                                push    80000001h       ; hKey
  6. .text:00601A64 FF 15 C0 23 6F 00                             call    ds:RegOpenKeyExA
  7. .text:00601A6A 85 C0                                         test    eax, eax
  8. .text:00601A6C 0F 85 AC 00 00 00                             jnz     loc_601B1E
  9. .text:00601A72 C7 84 24 BC 00 00 00 00 01 00 00              mov     [esp+0E4h+cbData], 100h
  10. .text:00601A7D 8D 84 24 BC 00 00 00                          lea     eax, [esp+0E4h+cbData]
  11. .text:00601A84 50                                            push    eax             ; lpcbData
  12. .text:00601A85 8D 84 24 BC 00 00 00                          lea     eax, [esp+0E8h+Type]
  13. .text:00601A8C 68 F8 3E 78 00                                push    offset userdir_path ; lpData
  14. .text:00601A91 50                                            push    eax             ; lpType
  15. ........

Работающий код:

Код: ASM
  1. .text:00601A52 90                                            nop
  2. .text:00601A53 68 50 BD 68 00                                push    _programPath
  3. .text:00601A58 90 90                                         nop
  4. .text:00601A5A 68 F8 3E 78 00                                push    userdir_path
  5. .text:00601A5F E8 FC 0A 04 00                                call    _strcpy
  6. .text:00601A64 90 90 90 90 90 90                             nop
  7. .text:00601A6A 90 90                                         nop
  8. .text:00601A6C 90 90 90 90 90 90                             nop
  9. .text:00601A72 90 90 90 90 90 90 90 90 90 90 90              nop
  10. .text:00601A7D 90 90 90 90 90 90 90                          nop
  11. .text:00601A84 59                                            pop    ecx
  12. .text:00601A85 90 90 90 90 90 90 90                          nop
  13. .text:00601A8С 90 90 90 90 90                                nop
  14. .text:00601A91 59                                            pop    ecx
  15. ........

Неработающий код:

Код: ASM
  1. .text:00601A52 68 50 BD 68 00                                push    _programPath
  2. .text:00601A57 68 F8 3E 78 00                                push    userdir_path
  3. .text:00601A5С E8 FF 0A 04 00                                call    _strcpy
  4. .text:00601A61 59                                            pop    ecx
  5. .text:00601A62 59                                            pop    ecx
  6. .text:00601A63 90 90 90 90 90 90 90 90 90 90 90+             nop
  7. ........

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 512
  • Репутация: +33/-0
    • Просмотр профиля
Pop - тоже надо нопить, ведь это выталкивание их стека... Конечно будут вылеты... Есть ли код целиком этого самого участка?

Оффлайн xanser

  • Главный Модератор
  • Опытный
  • *****
  • Сообщений: 498
  • Репутация: +43/-0
  • Есть такая профессия - на работе сидеть
    • Просмотр профиля
Код я собрал для примера, все это у меня в cpp подменивается побайтово. Глубину стэка я проверил, в примере идет блок считывания из реестра, т.е. в начале и в конце блока глубина стека например 0E4 (я просто не дописал и там много push в начале). Точно также в моей замене, в начале и в конце 0E4, внутри идет два push и два pop, чтобы восстановить уровень стека. Мой блок работает, но внутри команды с разрывами nop, как только я пытаюсь написать без разрывов, а nop до конца блока, кажется что код понимается уже по другому. Так вот про строки байтов - это принциально сохранить при замене длину команд в байтах или она не важна и ошибка была в чем-то другом?
« Последнее редактирование: Апрель 01, 2014, 05:19:22 pm от xanser »

Оффлайн Sektor

  • Администратор
  • Постоялец
  • *****
  • Сообщений: 512
  • Репутация: +33/-0
    • Просмотр профиля
Если говорить про строки, то туда в push передается адрес строки, т.е указатель 4 байта.