Рейтинг темы:
  • 1 Голос(ов) - 5 в среднем
  • 1
  • 2
  • 3
  • 4
  • 5
Модификация игры ASM/C++ Часть 5.
#1
Всем, привет!
В предыдущих частях мы подготовили нашу DLL и она уже может создавать солнцеSmile
Но нам нужно сделать конструктор и деструктор нашего объекта который создает солнце.

Для этого найдем конструктор, и перенесем инициализацию из функции sub_40D840 в настоящий конструктор.
На самом деле это функция другого класса, в которой инициализируеться наш объект.
К примеру это выглядит вот так

[SRC="c++"]
int __thiscall sub_4528B0(_DWORD *this)
{
v1 = this;
sub_452640((int)this);
v2 = operator new(0x57D8u);
if ( v2 )
v3 = sub_40A3C0(v1, (int)v2);
else
v3 = 0;
v4 = v1[49];
v5 = v1[48];
v1[538] = v3;
(*(void (__thiscall **)(int, _DWORD, _DWORD, int, int))(*(_DWORD *)v3 + 160))(v3, 0, 0, v5, v4);
(*(void (__stdcall **)(_DWORD))(*(_DWORD *)v1[200] + 12))(v1[538]);
(*(void (__stdcall **)(_DWORD))(*(_DWORD *)v1[200] + 48))(v1[538]);

return (*(int (__stdcall **)(_DWORD))(*(_DWORD *)v1[200] + 32))(v1[538]);
}

class FirstClass
{
/* .... */
/* 0A82 */ Creator* obj;
/* 0A86 */
public:
void func2(Creator*){};
void func3(Creator*){};
void func4(Creator*){};

void InitObj()
{
obj = new Creator;
obj->func1(0, 0, v5, v4);

func2(obj);
func3(obj);
func4(obj);
}
};
[/SRC]

И нам нужно перехватить конструктор вот этот

sub_40A3C0(v1, (int)v2);

Реализуем это в DLL.

[SRC="c++"]
LPVOID __fastcall Creator::Constructor(LPVOID lpPtr, LPVOID /* edx */, Creator* pCreator)
{
typedef Creator*(__thiscall *t)(LPVOID, Creator*);
t f = (t)0x0040A3C0;

g_Creator = pCreator;

Creator* pReturn = f(lpPtr, pCreator);
new (&pCreator->objCreatorEx) CreatorEx;

return pReturn;
}
[/SRC]

Несмотря на то что используется соглашение о вызове __thiscall, я использую __fastcall по одной довольно тупой причинеSmile
Когда статической функции указать соглашение о вызове __thiscall, она подсвечивается как ошибка, что мне не нравитсяSmile но при этом код компилируетсяSmile
Но я люблю когда в коде нет красных полосSmile

При __thiscall первый аргумент передается функции с помощью регистра ECX, все остальное через стек.
А __fastcall два первых аргумента передаются через регистры это тот же ECX, и еще EDX, все остальное через стек.
Если посмотреть у меня в коде EDX просто не используется.

Теперь реализуем деструктор.
[SRC="c++"]
void *__thiscall sub_40AF10(void *this, char a2)
{
void *v2; // esi@1

v2 = this;
sub_40AF40((int)this);
if ( a2 & 1 )
operator delete(v2);
return v2;
}
[/SRC]

Тоже самое как и с конструктором.
[SRC="c++"]
Creator* __fastcall Creator:Big Grinestructor(Creator* pCreator, LPVOID /* edx */, bool bIsMemoryFreeUsed)
{
if (g_Creator == pCreator)
g_Creator = NULL;

pCreator->objCreatorEx.~CreatorEx();

typedef Creator*(__thiscall *t)(Creator*, bool);
t f = (t)0x0040AF10;
return f(pCreator, bIsMemoryFreeUsed);
}[/SRC]

Так же я еще добавил функцию рандома.
[SRC="c++"]
int __cdecl Creator::GameRandom(int nRange)
{
typedef unsigned int(__cdecl *t)(int);
t f = (t)0x005FF2A0;
return f(nRange);
}[/SRC]

А функция void CreateSun(int a2, int a3, int a4, int a5);
Изменилась на
[SRC="c++"]
enum ItemType : long {
Sun25 = 4, Sun15, Sun50
};
enum ItemSpeed : long {
NORMAL = 0, SLOW
};
void CreateItem(int posX, int posY, ItemType item, ItemSpeed speed);[/SRC]

Вот функция которая создает солнце, и она же сразу же помещает его в массив

Показать код

я очень долго пытался понять что это за функция, предполагал что это std::array<CSun, 0x400>. Но больше всего это std::map<const char*, void*>;

Вот так место в памяти выделяется
Показать код

Знаю точно что v1 = *(_DWORD *)(a1 + 0xC); номер места в памяти где будет расположен следующий элемент, ++*(_DWORD *)(a1 + 0x10); количество итемов на текущий момент, v2 = *(_DWORD *)(a1 + 4); максимальное количество итемов(которое было)
Предположительно массив вот такой
[SRC="c++"]
struct Item
{
/* 0000 */ unsigned long __uUnkValue0000[54];
/* 00D8 */
};

struct ArrayItems
{
/* 0000 */ Item* arrSuns;
/* 0004 */ unsigned long dwMaxCount;
/* 0008 */ unsigned long dwCapacity;
/* 000C */ unsigned long dwNextPosition;
/* 0010 */ unsigned long dwCount;
/* 0014 */ char* szName = "coins";
/* 0018 */

ArraySuns()
{
dwCapacity = 0x400;
dwCount = 0xDF69; // Не понимаю почему
dwMaxCount = 0;
dwNextPosition = 0;

arrSuns = new Item[0x400];
}

~ArraySuns()
{
delete[] arrSuns;
}
};[/SRC]

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

Показать код

Теперь попробуем перехватить конструктор создания предмета. Можно перехватить вот здесь на моменте выделения памяти int __usercall sub_420D90@<eax>(int a1@<edi>)
Но это не конструктор, и мы не сможем поменять тогда значения на свои. А лишь получить адрес на объект.
Вот настоящий конструктор int __userpurge sub_432C60@<eax>(int a1@<eax>, int a2@<ecx>, Item* pItem, signed int X, signed int Y)
Обратите внимание на соглашение о вызове, это так же последствия оптимизации. Через EAX, передаётся тип предмета. А через ECX скорость движения нашего предмета.
Единственное что можно тут сделать так это написать функцию naked. Смотрим на код

Показать код

Записываем свой naked

WriteInstructionJmp(0x0040F443, (UINT)ItemNakedConstructor);

Теперь напишем функцию где будем отслеживать нажатие кнопки F5, после чего будем создавать солнцеSmile

[SRC="c++"]
DWORD WINAPI ThreadProc(LPVOID lpPtr)
{
while (true)
{
if (::GetAsyncKeyState(VK_F5) != 0)
{
if (g_Creator)
{
::Sleep(50);

g_Creator->objCreatorEx.PushSun();
}
}
}

return 0;
}
[/SRC]

Попробуем скомпилировать и запуститьSmile

И видим что солнце автоматически подбирается, вот видео где можно это посмотретьSmile

Видео

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

Так же у предмета есть функция которая возвращает время сколько предмет будет валяться на полу.

[SRC="c++"]unsigned int Item::GetMaxWaitTime(void)
{
typedef unsigned int(__thiscall *t)(Item*);
t f = (t)0x00435DA0;
return f(this);
}[/SRC]

Тем самым мы можем сделать так чтобы солнце пропадало сразу же после того как коснётся земли.
Сделать это можно вот так в конструкторе:

pItem->dwTimeWait = pItem->GetMaxWaitTime();

Жду ваши вопросыSmile

Так же сделал репозиторий с исходным кодом проекта.
GitHub

Если нужен исходник:
PlantsVsZombies.rar

1 часть
2 часть
3 часть
4 часть

Пересмотрел все возможные предметы, начиная от 7, лень было переименовывать Smile
Посмотреть код
Ответ
#2
Молодец, стараешься, давненько тут ничего толкового не было.
Ответ
#3
Было бы веселее если бы ты смог это повторить на движке L2, Там есть похожие фичи - регулируемые только движком игры, было бы больше интересующих голов !

Я как то пытался в C3, найти обработчик тулбар-шортактов , но меня хватило лишь на инвентарь
Было
Стало

и
Текстуру шортактов сломал, вместе с кнопками.

[Изображение: H4Kp1qe.png?2]

И чето как то бросил я :redlol:
Ответ
#4
luslighter Написал:тулбар-шортактов

Это внизу панель?
Ответ
#5
VOLKyiv Написал:Это внизу панель?

Она самая !
P.S.
Описание менющек кнопок и прочего, построено на каких то стандартных решениях от майков ,с использованием XML !
Ответ
#6
luslighter Написал:Она самая !
P.S.
Описание менющек кнопок и прочего, построено на каких то стандартных решениях от майков ,с использованием XML !

ну мне код смотреть надо, но больше всего там что-то вроде таблицы указателей на функцию.

[SRC="c++"]
typedef void(__cdecl *fPtr)(void);

struct Table
{
fPtr arr_fnc[10];
};
[/SRC]
Ответ
#7
VOLKyiv Написал:ну мне код смотреть надо, но больше всего там что-то вроде таблицы указателей на функцию.

[SRC="c++"]
typedef void(__cdecl *fPtr)(void);

struct Table
{
fPtr arr_fnc[10];
};
[/SRC]
Так то не просто XML, А уже скомпиленный XML с CPP, не помню точно как это называется, но раньше это юзали для построения GUI в 2000-ых.
Ответ
#8
luslighter Написал:Так то не просто XML, А уже скомпиленный XML с CPP, не помню точно как это называется, но раньше это юзали для построения GUI в 2000-ых.

Без кода бессиленSad

Добавлено через 20 минут
Для правильного подбора предмета добавил функцию, чтобы не писать вот так:

[SRC="c++"]pItem->nIsPickUp = TRUE;[/SRC]

что есть не правильно, вот собственно функция:

[SRC="c++"]void Item:TongueickUp(void)
{
typedef void(__thiscall *t)(Item*);
t f = (t)0x00434DC0;
f(this);
}[/SRC]
Ответ


Возможно похожие темы ...
Тема Автор Ответы Просмотры Последний пост
  Бот для игры kanmisha 6 1,719 01-28-2024, 06:17 PM
Последний пост: osazonov
  Модификация игры ASM/C++ Часть 4. VOLKyiv 7 3,119 07-28-2016, 01:50 AM
Последний пост: Deazer
  Модификация игры ASM/C++ Часть 3. VOLKyiv 0 1,900 07-27-2016, 02:22 PM
Последний пост: VOLKyiv
  Модификация игры ASM/C++ Часть 2. VOLKyiv 0 1,670 07-27-2016, 02:04 PM
Последний пост: VOLKyiv
  Модификация игры ASM/C++ Часть 1. VOLKyiv 0 2,773 07-27-2016, 01:59 PM
Последний пост: VOLKyiv

Перейти к форуму:


Пользователи, просматривающие эту тему: 1 Гость(ей)