Объявления

Друзья, если не получается зарегистрироваться, напишите на почту vdv_forever@bk.ru.
Я оторву свою задницу от всех дел и обязательно Вас активирую! :smile10:
Добро пожаловать на геройский форум! :smile25:

База данных IDA от void17

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 28 ноя 2021, 06:29

Короче, вот такой combatManager у меня сейчас:

 
Код: Выделить всё
#pragma pack(push, 1)
struct combatManager
{
  void *VMT;
  baseManager *NextManager;
  baseManager *PrevManager;
  int field_C;
  int orderIndex;
  char managerName[32];
  int attached;
  int (__thiscall ***func_ptr_0)(_DWORD, int);
  enum ECombatAction action;
  int actionParameter;
  int actionTargetHex;
  int actionParameter2;
  char accessableSquares[187];
  char accessableSquares2[187];
  char field_1C2;
  char field_1C3;
  hexcell squares[187];
  int landType;
  int field_5398;
  int cycleType;
  int absoluteObstacleID;
  int siegeKindStrange;
  bool hasMoat;
  bool hasDoubleMoat;
  char field_53AA;
  char field_53AB;
  void (__thiscall ***func_ptr_1)(_DWORD, int);
  Bitmap16Bit *drawBuffer;
  void (__thiscall ***func_ptr_2)(_DWORD, int);
  int doNotDrawShade;
  NewmapCell *mapItem;
  int specialGround;
  bool inAntiMagicGarrison;
  bool creatureBankBattle;
  bool battleOnWater;
  char field_53C7;
  town *town;
  hero *hero[2];
  int heroSpellPower[2];
  char field_53DC;
  char field_53DD;
  char field_53DE;
  char field_53DF;
  char field_53E0;
  char field_53E1;
  char field_53E2;
  char field_53E3;
  int heroAnimation[2];
  int heroAnimationFrame[2];
  char field_53F4;
  char field_53F5;
  char field_53F6;
  char field_53F7;
  char field_53F8;
  char field_53F9;
  char field_53FA;
  char field_53FB;
  int time_53FC;
  int time_5400;
  CSprite *heroDefLoaded[2];
  CSprite *heroFlagLoaded[2];
  int heroFlagCadre[2];
  RECT heroUpdateRect[2];
  RECT heroFlagUpdateRect[2];
  std::vector eagleEyeVector[2];
  bool massSpellTarget[2][20];
  bool isNotAI[2];
  bool isHuman[2];
  int heroOwner[2];
  bool hasArtifactAutoCast[2];
  bool wieldingAngelicAlliance[2];
  int heroCasted[2];
  int armyNum[2];
  armyGroup *armyGroup[2];
  army army[2][21];
  char f_1329C[4];
  int turnsSinceLastEnchanterCast[2];
  char _f_132A8[16];
  int currentMonSide;
  int currentMonIndex;
  int currentActiveSide;
  int autoCombat;
  army *activeStack;
  char blueHighlight;
  char _f_132CD[3];
  int creature_at_mouse_pos;
  int mouse_coord;
  int attacker_coord;
  int move_type;
  char _f_132E0[20];
  int siegeKind2;
  int finished;
  void *dlg;
  char f_13300[356];
  LPCSTR backgroundPcxName;
  H3AdjacentSquares adjacentSquares[187];
  char _f_13D2C[12];
  RECT updateRect;
  char _f_13D48[12];
  int cmNumWinPcxLoaded;
  std::vector obstacleInfo;
  bool tacticsPhase;
  char _f_13D69[3];
  int turn;
  int tacticsDifference;
  char _f_13D74[4];
  TownTowerLoaded Towers[3];
  int waitPhase;
  int heroDAttack;
  int heroDDefense;
  int heroDSpellPower;
  int HeroDSpellPoints;
  int TownPicturesLoaded[90];
  int fortWallsHP[18];
  int fortWallsIntact[18];
  char f_13FF0[4];
  void *cCellGrdPcx;
  void *cCellShdPcx;
  int globalCadreIndex;
  bool redrawCreatureFrame[2][20];
  bool heroAnim[2];
  bool heroFlagAnim[2];
  bool turretAnim[3];
  char f_14030[221];
};
#pragma pack(pop)
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 28 ноя 2021, 06:42

H3AdjacentSquares Замените на hexcell, а так, с пивом пойдет
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 28 ноя 2021, 07:16

Цитата:
H3AdjacentSquares Замените на hexcell

Тогда меняется размер combatManager :smile5: А какой правильный?

Нашёл:

Код: Выделить всё
v16 = operator new(0x140EC);
if ( v16 )
  v17 = combatManager::combatManager(v16);
else
  v17 = 0;

С hexcell вообще в районе 0x18000 получается, но и сейчас неправильный. Сейчас 0x1410C, т.е. почти :smile1:

У RoseKavalier заканчивается h3unk _f_14030[220]; Т.е. размер 0x14030 + 220 = 0x1410C, поэтому я перенёс всё правильно. Может, хвост убрать, там разница в 0x20 байтов. Сделал пока последние поля так:

Код: Выделить всё
int globalCadreIndex;
bool redrawCreatureFrame[2][20];
bool heroAnim[2];
bool heroFlagAnim[2];
bool turretAnim[3];
char f_14030[189];

Теперь размер 0x140EC.

* * *
Код: Выделить всё
total_hit_points = army::get_total_hit_points(v8, this->CombatParams->isBattleSimulated);

Вот тут вторым аргументом идёт bool, а не int. При false получаем текущее здоровье всего отряда, при true - после атаки (используется во время симуляции удара).

* * *
Обнаружил страшный косяк, который портил код, работающий с FPU. Да, ftol() возвращает __int64 в паре регистров eax:edx, но используется только eax часть! Эх, рано обрадовался, если поменять тип на int, IDA начинает вставлять __asm :smile29:

А вообще, зачем ftol() возвращать что-то в edx? :smile5: Так, я сломал ftol() :smile1: Короче, прописал всё, как было, т.е. тип __int64, даже заандефайнил функцию и создал снова и ту, которая использует ftol() тоже, но ассемблерные вставки не исчезли. Что за ерунда?
Последний раз редактировалось AlexSpl 28 ноя 2021, 08:53, всего редактировалось 1 раз.
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 28 ноя 2021, 08:49

IDA имеет ряд больших недоработок. Давайте напишем разработчикам, они прислушаются.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 28 ноя 2021, 09:06

Какой-то костыль с ftol() у IDA, похоже. Вернул, как было:

Код: Выделить всё
; Attributes: library function bp-based frame

    ; __int64 __thiscall ftol(void *this)
    ftol proc near

    var_C= qword ptr -0Ch
    var_4= word ptr -4
    var_2= word ptr -2

000 push    ebp
004 mov     ebp, esp
004 add     esp, 0FFFFFFF4h ; Add
010 fstcw   [ebp+var_2]     ; Store Control Word
010 wait                    ; Wait until BUSY# Pin is Inactive (HIGH)
010 mov     ax, [ebp+var_2]
010 or      ah, 0Ch         ; Logical Inclusive OR
010 mov     [ebp+var_4], ax
010 fldcw   [ebp+var_4]     ; Load Control Word
010 fistp   [ebp+var_C]     ; Store Integer and Pop
010 fldcw   [ebp+var_2]     ; Load Control Word
010 mov     eax, dword ptr [ebp+var_C]
010 mov     edx, dword ptr [ebp+var_C+4]
010 leave                   ; High Level Procedure Exit
000 retn                    ; Return Near from Procedure
    ftol endp

Но всё равно теперь декомпилирует не так, как раньше. А какая у ftol() сигнатура? Что-то мне не нравится __thiscall и void* аргумент. Эта функция берёт число из регистра FPU и делает его целым. Вот какой это __thiscall? Разве аргумент в ecx?

Вот как сама IDA декомпилирует ftol(). Даже до моих изменений:

Код: Выделить всё
__int64 __thiscall ftol(void *this)
{
  __int64 v2; // [esp+0h] [ebp-Ch]
  __int16 v3; // [esp+8h] [ebp-4h]
  __int16 v4; // [esp+Ah] [ebp-2h]

  __asm { fstcw   [ebp+var_2]; Store Control Word }
  v3 = v4 | 0xC00;
  __asm
  {
    fldcw   [ebp+var_4]; Load Control Word
    fistp   [ebp+var_C]; Store Integer and Pop
    fldcw   [ebp+var_2]; Load Control Word
  }
  return v2;
}
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 28 ноя 2021, 09:20

Всё. Вопрос закрыт. IDA поменяла сигнатуру моей функции.

А нет, рано обрадовался. Реально засада:

Код: Выделить всё
int __thiscall type_AI_spellcaster::get_disease_value(
        type_AI_spellcaster *this,
        const army *stack,
        type_enchant_data data)
{
  int result; // eax
  void *v6; // ecx
  void *v7; // ecx
  army *stackb; // [esp+18h] [ebp+8h]
  army *stacka; // [esp+18h] [ebp+8h]

  if ( ((1 << stack->sideIndex) & this->shootingThreats) == 0 )
    return 0;
  if ( this->combatParams.isOpponentDangerous )
    return 0;
  stackb = (army *)army::get_total_combat_value(
                     (army *)stack,
                     this->combatParams.enemyHeroAttack,
                     this->combatParams.enemyHeroDefense);
  __asm
  {
    fild    [ebp+stack]; Load Integer
    fstp    [ebp+var_8]; Store Real and Pop
    fld     [ebp+var_8]; Load Real
    fmul    ds:dbl_0063B7E0; Multiply Real
    fsubr   [ebp+var_8]; Subtract Real Reversed
    fild    [ebp+arg_10]; Load Integer
    fstp    [ebp+var_8]; Store Real and Pop
    fmul    [ebp+var_8]; Multiply Real
  }
  result = ftol(v6);
  stacka = (army *)result;
  if ( LOBYTE(data.army) )
  {
    combatManager::SpellCastWorkChance(gpCombatManager, SPL_WEAKNESS, this->side[0], stack, 0, 1, this->isCreatureCast);
    __asm
    {
      fild    [ebp+stack]; Load Integer
      fstp    [ebp+stack]; Store Real and Pop
      fmul    [ebp+stack]; Multiply Real
    }
    return ftol(v7);
  }
  return result;
}

До этого всё было OK. Реально ли как-то откатить? Похоже, теперь IDA считает ftol() функцией.

Ура, решил. Нужно было удалить сигнатуру ftol() и переанализировать. Теперь всё отлично:

Код: Выделить всё
int __thiscall type_AI_spellcaster::get_disease_value(
        type_AI_spellcaster *this,
        const army *stack,
        type_enchant_data data)
{
  __int64 v5; // rax
  int total_combat_value; // eax
  float stacka; // [esp+18h] [ebp+8h]

  if ( ((1 << stack->sideIndex) & this->shootingThreats) != 0 )
  {
    if ( this->combatParams.isOpponentDangerous )
    {
      LODWORD(v5) = 0;
    }
    else
    {
      total_combat_value = army::get_total_combat_value(
                             stack,
                             this->combatParams.enemyHeroAttack,
                             this->combatParams.enemyHeroDefense);
      v5 = ((total_combat_value - total_combat_value * 0.9) * data.SpellDuration);
      if ( LOBYTE(data.army) )
      {
        stacka = v5;
        return (combatManager::SpellCastWorkChance(
                  gpCombatManager,
                  SPL_WEAKNESS,
                  this->side[0],
                  stack,
                  0,
                  1,
                  this->isCreatureCast)
              * stacka);
      }
    }
  }
  else
  {
    LODWORD(v5) = 0;
  }
  return v5;
}

Правильная сигнатура ftol(): __int64 __usercall ftol@<edx:eax>(double a1@<st0>):
Код: Выделить всё
__int64 __usercall ftol@<edx:eax>(double a1@<st0>)
{
  return a1;
}

Прочитал про fistp. Есть разновидность, которая выталкивает из регистра FPU число не в пару регистров <edx:eax>, а только в eax. Вот она бы решила проблемы с такими странными локальными переменными, как __int64 v5; // rax, а главное, с дурацким приведением к __int64, но в Героях 3 реально используется вариант fistp, который выталкивает в пару регистров, а игнорировать edx в общем случае нельзя, хотя для округления в игре используется только eax. Эх, можно было бы это как-то декомпилятору подсказать...

В игре, короче, используется вариант DF /7 FISTP m64int - Store ST(0) in m64int and pop register stack. А нужен DB /3 FISTP m32int Store ST(0) in m32int and pop register stack. Можно даже хакнуть инструкцию в шестнадцатеричном редакторе, и я уверен, что декомпилированный листинг функций, использующих ftol(), будет намного читабельнее.

ftol() вызывается, когда программист пишет так, например:

Код: Выделить всё
int i = 1;

i = (int)(i * 3.14);

Вот такой эквивалент ftol() нашёл:

Код: Выделить всё
int ftol(float f)
{
    int a         = *(int*)(&f);
    int sign      = (a>>31);
    int mantissa  = (a&((1<<23)-1))|(1<<23);
    int exponent  = ((a&0x7fffffff)>>23)-127;
    int r         = ((unsigned int)(mantissa)<<8)>>(31-exponent);
    return ((r ^ (sign)) - sign ) &~ (exponent>>31);     
}

Это без переключения режимов округления и только для float (4 байта).

Чтобы заставить ftol() возвращать значение только в eax, нужно заменить fistp qword ptr [ebp-0Ch] (DF 7D F4) на DB 5D F4. Потом попробую создать IDA-базу с этим хаком и отпишусь о результатах.
Последний раз редактировалось AlexSpl 28 ноя 2021, 10:29, всего редактировалось 1 раз.
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 28 ноя 2021, 10:29

Какой геморрой. Я уже запутался, с чего все началось.
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 28 ноя 2021, 10:31

Короче, у меня идея хакнуть ftol(), чтобы эта функция возвращала результат округления только в регистре eax. Это даст более чистый листинг без всяких __int64. Саму игру лучше не трогать, а для декомпиляции полезная операция.
Вернуться к началу

offlineАватара пользователя
void_17  
имя: имя
Ветеран
Ветеран
 
Сообщения: 548
Зарегистрирован: 25 апр 2021, 15:05
Откуда: Оттуда
Пол: Мужчина
Поблагодарили: 132 раз.

Re: База данных IDA от void17

Сообщение void_17 » 28 ноя 2021, 10:38

AlexSpl писал(а):

А теоретически программеры NWC могли использовать шаблоны? Т.е. была в этом необходимость? Например, в базе Героев 2 с дебаг-инфо я не вижу шаблонов.

Я был не прав. NWC писали свои шаблоны. В героях 3(Dreamcast, но в SoD они тоже есть) нашел только два.
TAutoArrayPtr<...>
CAutoArray<...>

CAutoArray лежал в хедере array.h
TAutoArrayPtr лежал в хедере AutoArrayPtr.h
https://twitter.com/DiskBlitz/status/92 ... 69/photo/1

TAutoArrayPtr использовался лишь экземпляром
TAutoArrayPtr<char*> в функции bool InitializeCampaignMapTraitsTable(void)

CAutoArray<...> уже поинтереснее.
По крайней мере в дримкаст базе использовались следующие экземпляры шаблона:
CAutoArray<int>
CAutoArray<CDPlayConnection>
CAutoArray<CDPlayGroup>
CAutoArray<CDPlayPlayer>
CAutoArray<CDPlaySession>
CAutoArray<CDPlayAddressElement>
применялись много где.

Все эти типы следует разобрать. :smile5:
А эти два шаблоны я разберу сам и выложу скоро ввиде хедера
Последний раз редактировалось void_17 28 ноя 2021, 12:05, всего редактировалось 2 раз(а).
Вернуться к началу

offlineАватара пользователя
AlexSpl  
имя: Александр
Эксперт
Эксперт
 
Сообщения: 5587
Зарегистрирован: 17 сен 2010, 12:58
Пол: Мужчина
Награды: 14
Высшая медаль (1) Победителю турнира по HMM1_TE (2) Победителю этапа по HMM1 (1) Победителю этапа по HMM2 (1) Лучшему из лучших (1) 2 место 1 этапа по HMM1 (1)
3 место 1 этапа по HMM1 (1) 1 место 2 этапа по HMM2 (1) Победителю турнира по KB (2) Победителю турнира по KB (1) Грандмастер оффлайн-турниров (1) Боевой шлем (1)
Поблагодарили: 2185 раз.

Re: База данных IDA от void17

Сообщение AlexSpl » 28 ноя 2021, 10:43

Надо было ему по-тихому слить, но, скорее всего, захотел бабла от Ubisoft.
Вернуться к началу

Пред.След.

Вернуться в Общий раздел

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

cron