ASI фейковый фпс на сервере (monser dm, glow dm, blood dm и тд)

g305noobo

Известный
Автор темы
Модератор
281
419
Версия SA-MP
  1. Другая
описание: дает возможность подменить ваш фпс, который отображает сервер.
работает подменяя результат вызова функции GetDrunkLevel на нужное значение, благодаря которой сервер высчитывывает фпс.
активация:
/fakefps <fps от 5 до 400> | Если ввести без аргумента - вернет все по стандарту


зачем? зайдя на бразильский дм сервер (blood dm) был удивлён тому, что они до сих пор ограничивают игроков в фпсе, мол ставьте 100 фпс и ниже или не играйте =DDD
по приколу решил сделать это, возможно кому-то понадобится, вроде как есть есть аналог в LUA, но мне нужно было принципиально ASI, без зависимостей, а также в плюс поддержка всех версий сампа

впадлу было делить что-то, накидал все в одном ваще)))))
C++:
#include <iostream>
#include <windows.h>

#include <thread>
#include <string>
#include <random>

#include "minhook/include/MinHook.h"

class c_offsets {
public:
    c_offsets(std::uintptr_t base) {
        call_drunk_level = base;

        input = base; register_chat_command = base;
        chat = base; add_chat_msg = base;

        auto ver = _get_version(base);

        switch (ver) {
        case versions::r1:
            call_drunk_level += 0x5B32;

            input += 0x21A0E8;
            register_chat_command += 0x65AD0;

            chat += 0x21A0E4;
            add_chat_msg += 0x645A0;
            break;
        case versions::r2:
            call_drunk_level += 0x5B12;

            input += 0x21A0F0;
            register_chat_command += 0x65BA0;

            chat += 0x21A0EC;
            add_chat_msg += 0x64670;
            break;
        case versions::r3:
            call_drunk_level += 0x5B52;

            input += 0x26E8CC;
            register_chat_command += 0x69000;

            chat += 0x26E8C8;
            add_chat_msg += 0x679F0;
            break;
        case versions::r4:
            call_drunk_level += 0x5D36;

            input += 0x26E9FC;
            register_chat_command += 0x69730;

            chat += 0x26E9F8;
            add_chat_msg += 0x68130;
            break;
        case versions::r5:
            call_drunk_level += 0x5D46;

            input += 0x26EB84;
            register_chat_command += 0x69770;

            chat += 0x26EB80;
            add_chat_msg += 0x68170;
            break;
        }
    };

    std::uintptr_t call_drunk_level{};

    std::uintptr_t input{};
    std::uintptr_t register_chat_command{};

    std::uintptr_t chat{};
    std::uintptr_t add_chat_msg{};
private:
    enum versions {
        r1,
        r2,
        r3,
        r4,
        r5,
        unknown = -1
    };
    versions _get_version(std::uintptr_t base) {
        auto dos_header = reinterpret_cast<IMAGE_DOS_HEADER*>(base);
        if (!dos_header) return versions::unknown;

        auto nt_headers = reinterpret_cast<IMAGE_NT_HEADERS*>(base + dos_header->e_lfanew);
        auto ep = nt_headers->OptionalHeader.AddressOfEntryPoint;

        switch (ep) {
        case 0x31DF13: return versions::r1;
        case 0x3195DD: return versions::r2;
        case 0xCC490:  return versions::r3; // r0
        case 0xCC4D0:  return versions::r3; // r1
        case 0xCBCB0:  return versions::r4;
        case 0xCBC90:  return versions::r5;
        default:       return versions::unknown;
        }
    }
};

class c_samp {
public:
    using cmd_proc_t = void(__cdecl*)(const char*);
    c_offsets* p_offsets;

    c_samp(std::uintptr_t base) : p_offsets(new c_offsets(base)) {}

    bool is_inited() {
        _samp_input = *reinterpret_cast<c_samp_input**>(p_offsets->input);
        _samp_chat = *reinterpret_cast<c_samp_chat**>(p_offsets->chat);
        return _samp_input != nullptr && _samp_chat != nullptr;
    }

    void register_chat_command(const char* command, cmd_proc_t function) {
        reinterpret_cast<void(__thiscall*)(c_samp_input*, const char*, cmd_proc_t)>
            (p_offsets->register_chat_command)(_samp_input, command, function);
    }
    void add_chat_msg(std::uint32_t ulColor, const char* szText)
    {
        reinterpret_cast<void(__thiscall*)(c_samp_chat*, std::uint32_t, const char*)>
            (p_offsets->add_chat_msg)(_samp_chat, ulColor, szText);
    }
private:
    class c_samp_input* _samp_input{};
    class c_samp_chat* _samp_chat{};
};


class c_asi
{
public:
    c_asi();
    ~c_asi();
private:
    static std::uintptr_t _samp_base;
    static c_samp* _samp;

    static int _fps;
    static std::uint32_t _last_update;
    static std::uint32_t _drunk_level;

    static void (*p_game_loop)();

    static std::random_device _rd;
    static std::mt19937 _gen;
    static std::uniform_int_distribution<> _distrib;

    static int calc_drunk_level(int v) {
        if (_drunk_level <= _fps) _drunk_level = 2000;
        _drunk_level = _drunk_level - v;

        return _drunk_level * 256 + 184;
    }

    static void __cdecl game_loop() {
        static bool inited = false;

        if (!inited) {
            if (!_samp_base) _samp_base = (std::uintptr_t)GetModuleHandleA("samp.dll");

            if (_samp_base && !_samp) _samp = new c_samp(_samp_base);
            if (_samp && _samp->is_inited()) {
                _samp->register_chat_command("fakefps", &cmd_change_fps);

                inited = true;

            }
        }

        if (inited && _fps != 0) {
            auto current_ticks = GetTickCount();
            if (current_ticks - _last_update > 1000) {
                _last_update = current_ticks;

                auto new_val = calc_drunk_level(_fps);
                auto res = write_memory(_samp->p_offsets->call_drunk_level, new_val);
            }
        }
        p_game_loop();
    }

    static void msg(std::string s) {
        s = "{ff7581}[FakeFps]{e6e6e6} " + s;
        _samp->add_chat_msg(-1, s.c_str());
    }

    static void cmd_change_fps(const char* s) {
        try {
            std::uint32_t fps = std::stoi(s);
            if (fps > 400) {
                msg("Максимально 400 фпс");
                return;
            }
            else if (fps < 5) {
                msg("Минимально 5 фпс");
                return;
            }

            _fps = fps;
            msg("Фпс изменен на " + std::to_string(fps));

            auto val = calc_drunk_level(fps);
            write_memory(_samp->p_offsets->call_drunk_level, val);
        }
        catch (const std::invalid_argument& e) {
            if (_fps != 0) {
                msg("Используйте /fakefps <fps от 5 до 400> | Показатель fps возвращен");
                write_memory(_samp->p_offsets->call_drunk_level, 170723816);
                _fps = 0;
            } else msg("Используйте /fakefps <fps от 5 до 400>");
        };
    }

    static bool write_memory(uintptr_t adr, int val) {
        DWORD old_protect;
        if (VirtualProtect((LPVOID)adr, 4, PAGE_EXECUTE_READWRITE, &old_protect)) {
            memcpy((LPVOID)adr, &val, 4);
            VirtualProtect((LPVOID)adr, 4, old_protect, &old_protect);
            return true;
        }
        return false;
    }
}g_asi;


std::uintptr_t c_asi::_samp_base{};
c_samp* c_asi::_samp{};

std::uint32_t c_asi::_last_update{};
std::uint32_t c_asi::_drunk_level = 2000;
int c_asi::_fps{};

void (*c_asi::p_game_loop)() = nullptr;
std::random_device c_asi::_rd;
std::mt19937 c_asi::_gen(c_asi::_rd());
std::uniform_int_distribution<> c_asi::_distrib(-1, 1);

c_asi::c_asi()
{
    MH_Initialize();
    MH_CreateHook(reinterpret_cast<void*>(0x58A330), &game_loop, reinterpret_cast<void**>(&p_game_loop));
    MH_EnableHook(reinterpret_cast<void*>(0x58A330));

    _samp_base = (std::uintptr_t)GetModuleHandleA("samp.dll");
}

c_asi::~c_asi() {
    MH_RemoveHook(reinterpret_cast<void*>(0x58A330));
    write_memory(_samp->p_offsets->call_drunk_level, 170723816);
}
 

Вложения

  • fakefps.asi
    13.5 KB · Просмотры: 60

geniyeh

Известный
266
54
BLOOD DM anticheat:
exploding-head-emoticon-vector-45854957.jpg


good work on script!
 

histor

Известный
182
126
описание: дает возможность подменить ваш фпс, который отображает сервер.
работает подменяя результат вызова функции GetDrunkLevel на нужное значение, благодаря которой сервер высчитывывает фпс.
активация: /fakefps <fps от 5 до 400> | Если ввести без аргумента - вернет все по стандарту


зачем? зайдя на бразильский дм сервер (blood dm) был удивлён тому, что они до сих пор ограничивают игроков в фпсе, мол ставьте 100 фпс и ниже или не играйте =DDD
по приколу решил сделать это, возможно кому-то понадобится, вроде как есть есть аналог в LUA, но мне нужно было принципиально ASI, без зависимостей, а также в плюс поддержка всех версий сампа

впадлу было делить что-то, накидал все в одном ваще)))))
C++:
#include <iostream>
#include <windows.h>

#include <thread>
#include <string>
#include <random>

#include "minhook/include/MinHook.h"

class c_offsets {
public:
    c_offsets(std::uintptr_t base) {
        call_drunk_level = base;

        input = base; register_chat_command = base;
        chat = base; add_chat_msg = base;

        auto ver = _get_version(base);

        switch (ver) {
        case versions::r1:
            call_drunk_level += 0x5B32;

            input += 0x21A0E8;
            register_chat_command += 0x65AD0;

            chat += 0x21A0E4;
            add_chat_msg += 0x645A0;
            break;
        case versions::r2:
            call_drunk_level += 0x5B12;

            input += 0x21A0F0;
            register_chat_command += 0x65BA0;

            chat += 0x21A0EC;
            add_chat_msg += 0x64670;
            break;
        case versions::r3:
            call_drunk_level += 0x5B52;

            input += 0x26E8CC;
            register_chat_command += 0x69000;

            chat += 0x26E8C8;
            add_chat_msg += 0x679F0;
            break;
        case versions::r4:
            call_drunk_level += 0x5D36;

            input += 0x26E9FC;
            register_chat_command += 0x69730;

            chat += 0x26E9F8;
            add_chat_msg += 0x68130;
            break;
        case versions::r5:
            call_drunk_level += 0x5D46;

            input += 0x26EB84;
            register_chat_command += 0x69770;

            chat += 0x26EB80;
            add_chat_msg += 0x68170;
            break;
        }
    };

    std::uintptr_t call_drunk_level{};

    std::uintptr_t input{};
    std::uintptr_t register_chat_command{};

    std::uintptr_t chat{};
    std::uintptr_t add_chat_msg{};
private:
    enum versions {
        r1,
        r2,
        r3,
        r4,
        r5,
        unknown = -1
    };
    versions _get_version(std::uintptr_t base) {
        auto dos_header = reinterpret_cast<IMAGE_DOS_HEADER*>(base);
        if (!dos_header) return versions::unknown;

        auto nt_headers = reinterpret_cast<IMAGE_NT_HEADERS*>(base + dos_header->e_lfanew);
        auto ep = nt_headers->OptionalHeader.AddressOfEntryPoint;

        switch (ep) {
        case 0x31DF13: return versions::r1;
        case 0x3195DD: return versions::r2;
        case 0xCC490:  return versions::r3; // r0
        case 0xCC4D0:  return versions::r3; // r1
        case 0xCBCB0:  return versions::r4;
        case 0xCBC90:  return versions::r5;
        default:       return versions::unknown;
        }
    }
};

class c_samp {
public:
    using cmd_proc_t = void(__cdecl*)(const char*);
    c_offsets* p_offsets;

    c_samp(std::uintptr_t base) : p_offsets(new c_offsets(base)) {}

    bool is_inited() {
        _samp_input = *reinterpret_cast<c_samp_input**>(p_offsets->input);
        _samp_chat = *reinterpret_cast<c_samp_chat**>(p_offsets->chat);
        return _samp_input != nullptr && _samp_chat != nullptr;
    }

    void register_chat_command(const char* command, cmd_proc_t function) {
        reinterpret_cast<void(__thiscall*)(c_samp_input*, const char*, cmd_proc_t)>
            (p_offsets->register_chat_command)(_samp_input, command, function);
    }
    void add_chat_msg(std::uint32_t ulColor, const char* szText)
    {
        reinterpret_cast<void(__thiscall*)(c_samp_chat*, std::uint32_t, const char*)>
            (p_offsets->add_chat_msg)(_samp_chat, ulColor, szText);
    }
private:
    class c_samp_input* _samp_input{};
    class c_samp_chat* _samp_chat{};
};


class c_asi
{
public:
    c_asi();
    ~c_asi();
private:
    static std::uintptr_t _samp_base;
    static c_samp* _samp;

    static int _fps;
    static std::uint32_t _last_update;
    static std::uint32_t _drunk_level;

    static void (*p_game_loop)();

    static std::random_device _rd;
    static std::mt19937 _gen;
    static std::uniform_int_distribution<> _distrib;

    static int calc_drunk_level(int v) {
        if (_drunk_level <= _fps) _drunk_level = 2000;
        _drunk_level = _drunk_level - v;

        return _drunk_level * 256 + 184;
    }

    static void __cdecl game_loop() {
        static bool inited = false;

        if (!inited) {
            if (!_samp_base) _samp_base = (std::uintptr_t)GetModuleHandleA("samp.dll");

            if (_samp_base && !_samp) _samp = new c_samp(_samp_base);
            if (_samp && _samp->is_inited()) {
                _samp->register_chat_command("fakefps", &cmd_change_fps);

                inited = true;

            }
        }

        if (inited && _fps != 0) {
            auto current_ticks = GetTickCount();
            if (current_ticks - _last_update > 1000) {
                _last_update = current_ticks;

                auto new_val = calc_drunk_level(_fps);
                auto res = write_memory(_samp->p_offsets->call_drunk_level, new_val);
            }
        }
        p_game_loop();
    }

    static void msg(std::string s) {
        s = "{ff7581}[FakeFps]{e6e6e6} " + s;
        _samp->add_chat_msg(-1, s.c_str());
    }

    static void cmd_change_fps(const char* s) {
        try {
            std::uint32_t fps = std::stoi(s);
            if (fps > 400) {
                msg("Максимально 400 фпс");
                return;
            }
            else if (fps < 5) {
                msg("Минимально 5 фпс");
                return;
            }

            _fps = fps;
            msg("Фпс изменен на " + std::to_string(fps));

            auto val = calc_drunk_level(fps);
            write_memory(_samp->p_offsets->call_drunk_level, val);
        }
        catch (const std::invalid_argument& e) {
            if (_fps != 0) {
                msg("Используйте /fakefps <fps от 5 до 400> | Показатель fps возвращен");
                write_memory(_samp->p_offsets->call_drunk_level, 170723816);
                _fps = 0;
            } else msg("Используйте /fakefps <fps от 5 до 400>");
        };
    }

    static bool write_memory(uintptr_t adr, int val) {
        DWORD old_protect;
        if (VirtualProtect((LPVOID)adr, 4, PAGE_EXECUTE_READWRITE, &old_protect)) {
            memcpy((LPVOID)adr, &val, 4);
            VirtualProtect((LPVOID)adr, 4, old_protect, &old_protect);
            return true;
        }
        return false;
    }
}g_asi;


std::uintptr_t c_asi::_samp_base{};
c_samp* c_asi::_samp{};

std::uint32_t c_asi::_last_update{};
std::uint32_t c_asi::_drunk_level = 2000;
int c_asi::_fps{};

void (*c_asi::p_game_loop)() = nullptr;
std::random_device c_asi::_rd;
std::mt19937 c_asi::_gen(c_asi::_rd());
std::uniform_int_distribution<> c_asi::_distrib(-1, 1);

c_asi::c_asi()
{
    MH_Initialize();
    MH_CreateHook(reinterpret_cast<void*>(0x58A330), &game_loop, reinterpret_cast<void**>(&p_game_loop));
    MH_EnableHook(reinterpret_cast<void*>(0x58A330));

    _samp_base = (std::uintptr_t)GetModuleHandleA("samp.dll");
}

c_asi::~c_asi() {
    MH_RemoveHook(reinterpret_cast<void*>(0x58A330));
    write_memory(_samp->p_offsets->call_drunk_level, 170723816);
}
Где мем в теме? 😡
 
  • Нравится
Реакции: g305noobo