Current time: 15.04.2024, 07:07 Hello There, Guest! (LoginRegister)
Language: english | russian  

Post Reply 
Threaded Mode | Linear Mode
Программирование ВОГ
Author Message
baratorch Offline

Posts: 197
Post: #46

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

Code:
class Code
{
private:
    static DWORD protect;
    static LPVOID adress;
    static SIZE_T size;

public:
    enum HOOK_TYPE
    {
        JUMP, CALL
    };

    static void BeginWrite(DWORD adress, DWORD size);
    static void EndWrite();

    static void Write(DWORD adress, BYTE value);
    static void Write(DWORD adress, WORD value);
    static void Write(DWORD adress, DWORD value);
    static void WriteAdd(DWORD adress, DWORD value);
    static void Hook(DWORD adress, LPVOID procedure, HOOK_TYPE type);
};

Code:
void Code::BeginWrite(DWORD a, DWORD s)
{
    adress = (LPVOID)a;
    size = (SIZE_T)s;
    VirtualProtect(adress, size, PAGE_READWRITE, &protect);
}

void Code::EndWrite()
{
    VirtualProtect(adress, size, protect, NULL);
}

void Code::Write(DWORD adress, BYTE value)
{
    *(LPBYTE)adress = value;
}

void Code::Write(DWORD adress, WORD value)
{
    *(LPWORD)adress = value;
}

void Code::Write(DWORD adress, DWORD value)
{
    *(LPDWORD)adress = value;
}

void Code::WriteAdd(DWORD adress, DWORD value)
{
    *(LPDWORD)adress += value;
}


void Code::Hook(DWORD adress, LPVOID procedure, HOOK_TYPE type)
{
    if (type == HOOK_TYPE::JUMP)
        Write(adress, (BYTE)0xE9); //write JMP opcode
    else //if (type == HOOK_TYPE::CALL)
        Write(adress, (BYTE)0xE8); // write CALL opcode
    Write(adress + 1, (DWORD)procedure - adress - 5);
}

Code:
void Patch()
{

// ...

    Code::BeginWrite(0x401000, 0x239000);

// ...

    // ADVMAN window size - FS
    Code::Write((0x401530 + 1), (DWORD)screen_Height);
    Code::Write((0x401537 + 1), (DWORD)screen_Width);

    // ADVMAN window: world view size
    Code::WriteAdd((0x401608 + 1), (DWORD)common_stretching_Y);
    Code::WriteAdd((0x40160d + 1), (DWORD)common_stretching_X);

// ...

    Code::EndWrite();
}
(This post was last modified: 28.02.2010 02:14 by baratorch.)
28.02.2010 00:36
Find all posts by this user Quote this message in a reply
etoprostoya Offline

Posts: 1809
Post: #47

Наверное, лучше вместо перегрузки Write, сделать Write32, Write16, Write8 или WriteDword, WriteWord, WriteByte. Дабы не запутаться и нагляднее. Но это дело привычек, вкуса. По-моему, так класс - это лишнее.
Добавлено:
Я так говорю, потому что предпочитаю С, а не С++.
(This post was last modified: 28.02.2010 00:47 by etoprostoya.)
28.02.2010 00:45
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #48

Quote:Наверное, лучше вместо перегрузки Write, сделать Write32, Write16, Write8 или WriteDword, WriteWord, WriteByte. Дабы не запутаться и нагляднее
согласен, так и сделаю

Ну класс здесь вобщем-то и не класс, он выступает в роли namespace, и просто объединяет по смыслу несколько функций. Он для той же наглядности.
28.02.2010 00:58
Find all posts by this user Quote this message in a reply
GrayFace Offline
Forum Moderators

Posts: 1233
Post: #49

А в ВоГе и без VirtualProtect код Героев можно менять.
28.02.2010 09:38
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #50

блин, оказывается я не могу в VC++ 2005 прямо вызвать геройскую функцию.
т.е. вот таким образом:

call 0x41AFA0

пришлось извратится вот так:

Code:
typedef void (*SIMPLE_FUNC)(void*);

SIMPLE_FUNC Func_41AFA0 = (SIMPLE_FUNC)0x41AFA0;

void ModFunc_41AFA0()
{
    __asm
    {
        push ebp
        mov ebp, esp
        mov eax, dword ptr ss:[ebp+0x18]
        push eax
        mov eax, dword ptr ss:[ebp+0x14]
        push eax
        mov eax, dword ptr ss:[ebp+0x10]
        push eax
        mov eax, dword ptr ss:[ebp+0x0c]
        add eax, common_centering_Y
        push eax
        mov eax,dword ptr ss:[ebp+0x08]
        add eax, common_centering_X
        push eax
        call Func_41AFA0
        pop ebp
        retn 0x14
    }
}

может все-таки можно это сделать прямо?
28.02.2010 12:46
Find all posts by this user Quote this message in a reply
feanor Offline

Posts: 622
Post: #51

Quote:может все-таки можно это сделать прямо?
указатель на функцию с явным указанием способа передачи параметров?
28.02.2010 19:41
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16471
Post: #52

Угу. На Паскале:
Code:
TSomeFunc = PROCEDURE (i: integer; b: boolean); STDCALL;
VAR f: TSomeFunc;

f:=TSomeFunc($401000);
f(5, TRUE);


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
28.02.2010 19:46
Find all posts by this user Quote this message in a reply
Дьякон Offline

Posts: 392
Post: #53

На с++

    typedef void (*PFUNC) (int i);
    PFUNC pFunc;
   

    pFunc = (PFUNC)0x401000;
    pFunc(i);


Страус труп (с) Бьерн
01.03.2010 20:51
Find all posts by this user Quote this message in a reply
feanor Offline

Posts: 622
Post: #54

или так, по типу библиотеки функций:

__fastcall int (*ShowMSG)(const char *text, int type, int f1, int f2, int f3, int f4, int f5, int f6, int f7, int f8, int f9, int f10) =
    (__fastcall int (*)(const char*, int, int, int, int, int, int, int, int, int, int, int))(0x4F6C00);

__cdecl void (*CallERM)(int num) =
    (__cdecl void(*)(int))(0x74CE30);

....
ShowMSG(buf,MSG_RIGHT_CLICK,-1, -1, -1, 0, -1, 0, -1, 0, -1, 0);
CallERM(4001);
01.03.2010 22:34
Find all posts by this user Quote this message in a reply
GrayFace Offline
Forum Moderators

Posts: 1233
Post: #55

(28.02.2010 12:46)baratorch Wrote:  call 0x41AFA0
А это, по идее, никакой язык не позволит, т.к. смещение будет относительным и при загрузке dll по другому адресу "поплывет".
Достаточно объявить переменную любого подходящего типа. Например,
int SomeHeroesProc = 0x41AFA0

в __asm:
call SomeHeroesProc

Но лучше, конечно, как советуют, объявить функцией с верной сигнатурой, если может понадобиться вызов из не-асм кода.
03.03.2010 21:22
Find all posts by this user Quote this message in a reply
baratorch Offline

Posts: 197
Post: #56

о, да, я именно об этом спрашивал.

Quote:А это, по идее, никакой язык не позволит, т.к. смещение будет относительным и при загрузке dll по другому адресу "поплывет".

Действительно, как я сам об этом не подумал..

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

У меня тут еще проблема одна была с внедрением своего высокоуровневого кода в героев, оказывается у меня в настройках проекта все функции по умолчанию были __cdecl (а все геройские то __stdcall), а я этого не знал, не знал вообще что значат эти __cdecl, __stdcall но все же сделал рабочий длл. Теперь придется переделывать, чтобы ничего не было через Ж.

Кстати, как быть с геройискими функциями, у которых один аргумент передается в регистре ecx. Я ж не могу объявить функцию с есх аргументом, да? Тоесть при вызове такой функции из не асм кода все равно предется MOVать в ЕСХ аргумент?

И вот еще вопрос.
Мой патчер из bmp кусочков склеивал картинку под нужное разрешение, и сохранял ее в формате Zsoft PCX в папке Дата. А теперь при переходе на Длл смысла сохранять картинку в файл нет. Нужно чтобы ее клеила Длл и конвертила в формат загруженного героями PCX. В этом формате я вроде бы разобрался, у него вроде как палитра записана 16-ти битными цветами, кто знает какой там формат цвета - 565, 4444 или че другое?

Спасибо!
03.03.2010 23:59
Find all posts by this user Quote this message in a reply
etoprostoya Offline

Posts: 1809
Post: #57

В ECX-регистр по стандарту С++ для функции, принадлежащей классу, засовывается указатель (this) на этот класс. В таком случае имеет смысл создать класс(ы), в который(е) поставляются данные.
04.03.2010 00:08
Find all posts by this user Quote this message in a reply
Berserker Offline
Administrators

Posts: 16471
Post: #58

ecx - объект, __thiscall. Если ecx и edx содержат первые два параметра процедуры, то это соглашение __fastcall.


Скачать Герои 3 Эра и всё, что с ней связано / ERA 2.46f для старых модов
Поддержать проект
04.03.2010 00:13
Find all posts by this user Quote this message in a reply
etoprostoya Offline

Posts: 1809
Post: #59

Quote:On the Microsoft Visual C++ compiler, the this pointer is passed in ECX and it is the callee that cleans the stack, mirroring the stdcall convention used in C for this compiler and in Windows API functions. When functions use a variable number of arguments, it is the caller that cleans the stack (cf. cdecl).
04.03.2010 00:22
Find all posts by this user Quote this message in a reply
feanor Offline

Posts: 622
Post: #60

Quote:а все геройские то __stdcall
не все.
Quote:Кстати, как быть с геройискими функциями, у которых один аргумент передается в регистре ecx. Я ж не могу объявить функцию с есх аргументом, да? Тоесть при вызове такой функции из не асм кода все равно предется MOVать в ЕСХ аргумент?
Опять таки надо юзать fastcall (см.выше пример с ф-ей показа сообщения), тогда первые два параметра будут в ecx и edx.
Quote:On the Microsoft Visual C++ compiler, the this pointer is passed in ECX and it is the callee that cleans the stack, mirroring the stdcall convention used in C for this compiler and in Windows API functions. When functions use a variable number of arguments, it is the caller that cleans the stack (cf. cdecl).
А разговор идет не о них.
(This post was last modified: 04.03.2010 00:40 by feanor.)
04.03.2010 00:37
Find all posts by this user Quote this message in a reply
« Next Oldest | Next Newest »
Post Reply 


Forum Jump:

Powered by MyBB Copyright © 2002-2024 MyBB Group