• У форума будет новый домен? Да, мы далеко уже не только игровой форум Подробнее...
Иконка ресурса

[INC] Memory Extended 2.7

Нет прав для скачивания
Позволяет вмешиваться в работу сервера несколько более изощрёнными путями.
Поддерживаемые игры
  1. CS: GO
Первое что хотелось бы сказать, что философия данного inc состоит в том, чтобы все манипуляции воспроизводились без создания и нужды дополнительных файлов на сервере.
Данный INC находится в разработке и из-за этого - WINDOWS ONLY. Он был выложен для показа возможностей библиотеки, а так же возможной обратной связи
С версии 2.0 - добавлена поддержка linux

Данное "оружие" было создано для удобной работы с другими .dll, ведь в функциях SourcePawn можно работать только с 3-мя => server.dll/engine.dll/matchmaking_ds
Что же из этого вышло? - Давайте рассмотрим его структуру =>
С версии 2.0 структура разделена по файлами

MemoryEx/ASM_Instruction.inc - Вспомогающий файл, который позволяет использовать самые частые ASM функции в SP [Подключает за собою MemoryEx/BaseMemory.inc]

Код:
enum ASMRegister
{
    ASMRegister_EAX,
    ASMRegister_ECX,
    ASMRegister_EDX,
    ASMRegister_EBX,
    ASMRegister_ESP,
    ASMRegister_EBP,
    ASMRegister_ESI,
    ASMRegister_EDI
}

enum struct ASMInstructions
{
    BaseMemory mem;

    void Set(Pointer adr)
    {
        this.mem.pAddrBase = adr;
    }
    Pointer Get()
    {
        return this.mem.pAddrBase;
    }

    void PushRegister(ASMRegister reg)
    {
        this.mem.WriteByte(0x50 + view_as<int>(reg),     _,     MemoryEx_AddAfterWrite);
    }
    void Push(any value)
    {
        this.mem.WriteByte(0x68,     _,     MemoryEx_AddAfterWrite);
        this.mem.WriteInt(value,    _,     MemoryEx_AddAfterWrite);
    }
    void PopRegister(ASMRegister reg)
    {
        this.mem.WriteByte(0x58 + view_as<int>(reg),     _,     MemoryEx_AddAfterWrite);
    }

    void Call (any value)
    {
        this.mem.WriteWord(0x15FF,     _, MemoryEx_AddAfterWrite);
        this.mem.WriteInt(value,    _,     MemoryEx_AddAfterWrite);
    }

    void Nop()
    {
        this.mem.WriteByte(0x90,     _,     MemoryEx_AddAfterWrite);
    }
    void Xchg(ASMRegister reg)
    {
        this.mem.WriteByte(0x90 + view_as<int>(reg),     _,     MemoryEx_AddAfterWrite);
    }
    void Retn()
    {
        this.mem.WriteByte(0xC3,    _,    MemoryEx_AddAfterWrite);
    }
}

stock ASMInstructions g_ASM;

#define ASM g_ASM

#define ASMHELP_SET(%0)            g_ASM.Set(%0)
#define ASMHELP_GET()            g_ASM.Get()
#define PUSH_REGISTER(%0)         g_ASM.PushRegister(ASMRegister_%0)
#define PUSH(%0)                 g_ASM.Push(%0)
#define POP_REGISTER(%0)         g_ASM.PopRegister(ASMRegister_%0)
#define CALL(%0)                 g_ASM.Call(%0)
#define NOP()                     g_ASM.Nop()
#define XCHG(%0)                 g_ASM.Xchg(ASMRegister_%0)
#define RETN()                     g_ASM.Retn()
2) MemoryEx/BaseMemory.inc - Реализовывает базовые функции для более удобной работы с памятью
3) MemoryEx/DynamicLibrary.inc - Реализует функции для работы с динамическими библиотеками [
4) MemoryEx/ServerLibrary.inc - Работа с server[.so]/[.dll] - а именно получения базового адреса [Windows Only] (Для Linux не нужен) / Получение OS сервера
5) MemoryEx/LinuxFunction.inc - Вспомогательные функции для linux => Загрузка списка .so библиотек
6) MemoryEx/WindowsFunction.inc - Функции для Windows => Получения размера DLL из PEB заголовка/Получения версии Windows

Плагины работающие с MemoryEx
1) Bypass -nobots/-nohltv
2) SM Plugins Block [Путем патча самого SourceMod]

Самая интересная функция как по мне -> Pointer GetModuleHandle(const char[] name) которая вызывает и возвращает результат WINAPI GetModuleHandleW через SourcePawn :)

Данный INC вызывает WINAPI функцию GetModuleHandleW для получения Base Address любой библиотеки. Что же она делает?
Как можно заметить - первым аргументом она принимает название библиотеки, но для использования GetModuleHandleW - нужна unicode строка? - По этому и была создана функция MemoryEx::WriteUnicodeString.
В свободной памяти мы генерируем данную строку, делаем небольшой отступ [0x10] и мы должны создать функцию, которая вызывает ее, псевдокод на ASM =>
Код:
push [string address]
call dword ptr [GetModuleHandleW]
retn
Что же inc делает?
GetModuleHandleW в server.dll используется в двух случаях и во всех - использует kernel32. По этому мы ищем адрес данной строки, и можно использовать MemoryEx::FindString, но т.к это unicode - используем MemoryEx::FindUnicodeString. После того, как мы нашли адрес данной строки - ищем где используется данная строка через MemoryEx::FindValue, так же можно заметить, что последним аргументом в данной функции вспомогательный байт 0x
Код:
.text:1072C378 56                                      push    esi
.text:1072C379 68 EC D5 79 10                          push    offset aKernel32Dll_0 ; "kernel32.dll"
.text:1072C37E FF 15 F4 E0 78 10                       call    ds:GetModuleHandleW
Если проанализировать где используется данная строка, всегда после нее идет call ds:GetModuleHandleW т.е первый байт = 0xFF.
И так, узнали где используется kernel32.dll - теперь делаем смещение + 0x6 и тем самым загружаем адрес GetModuleHandleW. И так, как же это выглядит в библиотеке? =>
Код:
Pointer pKernelStr = this.FindUnicodeString("server", "kernel32.dll");
Pointer module = this.FindValue("server", pKernelStr, 0xFF)  + PTR(0x06);

if(pKernelStr == nullptr || module == nullptr)
{
    this.ChangeSettings(false);
    LogStackTrace("GetModuleHandles failed -> Base = 0x%X pKernelStr 0x%X module 0x%X end = 0x%X", g_ServerDLL.base, pKernelStr, module, g_ServerDLL.base + PTR(g_ServerDLL.size) );
    return nullptr;
}

module = PTR(LoadFromAddress(module, NumberType_Int32));
Дальнейшие действия такие:
Код:
        static int offsetForString = 0x10; // offset between string and function
        static int offsetForEnd = 0x100;

        int iLengthStr = strlen(name);

        //Теперь нужно перейти на адрес куда мы можем нужную строку + саму функцию.
        this.SetAddr((view_as<int>(g_ServerDLL.base) + g_ServerDLL.size) - offsetForEnd - offsetForString - (iLengthStr * 2)); // Address for string
        Pointer pString = this.GetAddr();

        // this.WriteUnicodeString(name) возвращает нам адрес, куда была записан последний байт строки и делаем маленькое смещения для написания уже самой функции.
        this.SetAddr( this.WriteUnicodeString(name) + PTR(offsetForString));


        Pointer pFunc = this.GetAddr();

        // Реализуем функцию из псевдокода, который был выше
        this.WriteByte(0x68,     _,     MemoryEx_AddAfterWrite); // push
        this.WriteInt(pString,    _,     MemoryEx_AddAfterWrite); // Адрес записаной unicode строки
        this.WriteWord(0x15FF,    _,     MemoryEx_AddAfterWrite); // call dword ptr
        this.WriteInt(module,    _,     MemoryEx_AddAfterWrite); // Адрес GetModuleHandleW
        this.WriteByte(0xC3,    _,    MemoryEx_AddAfterWrite); // retn
Чтобы было более понятно, в итоге это привело к этому: Далее просто вызываем ее через SDKCall и получаем Base Address любой интересующей нас dll
Код:
StartPrepSDKCall(SDKCall_Static);
PrepSDKCall_SetAddress(pFunc);
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);

Handle h = EndPrepSDKCall();
Pointer iRes = SDKCall(h);
Описании некоторых функций:
Данную функцию вы должны вызывать при инициализации MemoryEx, в ней определяется OS сервера, base address + size server.dll/.so.
Это позволяет использовать все функции из данной библиотеки.

Если вы попробуйте найтм какую-то строку, но не сделаете MemoryEx::Init() то ваш плагин будет вызывать подобную ошибку
Код:
L 12/18/2019 - 19:33:28: [SM] Stack trace requested: MemoryEx wasn't be initialized
L 12/18/2019 - 19:33:28: [SM] Called from: nobots_bypass.smx
L 12/18/2019 - 19:33:28: [SM] Call stack trace:
L 12/18/2019 - 19:33:28: [SM]   [0] LogStackTrace
L 12/18/2019 - 19:33:28: [SM]   [1] Line 437, E:\server\bhopserver\csgo\addons\sourcemod\records\2\include\MemoryEx.inc::MemoryEx::GetModuleSize
L 12/18/2019 - 19:33:28: [SM]   [2] Line 735, E:\server\bhopserver\csgo\addons\sourcemod\records\2\include\MemoryEx.inc::MemoryEx::FindString
L 12/18/2019 - 19:33:28: [SM]   [3] Line 18, nobots_bypass.sp::OnPluginStart
MemoryEx::SaveBytes(bool) - Нужно ли сохранять байты, которые были изменены в ходе работы плагина.

MemoryEx::NeedSave - true - Включена необходимость сохранять байты

MemoryEx::RestoreBytes - восстанавливает все измененные байты.
Пример:
Код:
#include <MemoryEx>

MemoryEx g_hMem;

public void OnPluginStart()
{
    RegServerCmd("sm_nobots", Cmd_NoBots);
}
public Action Cmd_NoBots(int iArgs)
{
    if(iArgs)
    {
        g_hMem.RestoreBytes();
    }
    else
    {
        if(g_hMem.Init())
        {
            g_hMem.SaveBytes(true);

            Pointer pEnd = g_hMem.GetBaseAddress("server") + PTR(g_hMem.GetModuleSize("server"));
            g_hMem.SetAddr(pEnd - PTR(0x200));

            g_hMem.WriteString("Memory", _, MemoryEx_AddAfterWrite);
            g_hMem.WriteUnicodeString("Extended", _, MemoryEx_AddAfterWrite);
            g_hMem.WriteByte(0x31, _, MemoryEx_AddAfterWrite);
            g_hMem.WriteWord(0x32, _, MemoryEx_AddAfterWrite);
            g_hMem.WriteInt(0x33, _, MemoryEx_AddAfterWrite);
        }
    }

}
Pointer GetModuleHandle(const char[] library) - Возвращает Base Address указанного модуля [На основе WINAPI GetModuleHandleW]. "0" - Возвращает адрес srcds.

Pointer InitModule(const char[] library) - Инициализирует Base/End address указанного модуля

Pointer GetBaseAddress(const char[] library) - Возвращает Base Address уже из инициализированного модуля

int GetModuleSize(const char[] library) - Возвращает инициализированный размер библиотеки

Pointer GetEndModule(const char[] library) - Возвращает адресс последнего инициализированного байта библиотеки [MemoryEx::GetBaseAddress + MemoryEx::GetBaseAddres]

Пример всех этих функций:
Код:
#include <MemoryEx>

public void OnPluginStart()
{
    MemoryEx mem;

    if(!mem.Init()) return;

    Pointer base = mem.GetModuleHandle("kernel32.dll");
    Pointer base1 = mem.InitModule("kernel32.dll");
    Pointer base2 = mem.GetBaseAddress("kernel32.dll");

    Pointer srcds = mem.GetModuleHandle("0");

    int size = mem.GetModuleSize("kernel32.dll");

    Pointer end1 = base1 + PTR(size);
    Pointer end2 = mem.GetEndModule("kernel32.dll");

    PrintToServer("base [0x%X] == base1 [0x%X] == base2 [0x%X] size [0x%X] end1 [0x%X] == end2 [0x%X] srcds [0x%X]", base, base1, base2, size, end1, end2, srcds);
}
Результат

base [0x75170000] == base1 [0x75170000] == base2 [0x75170000] size [0xE0000] end1 [0x75250000] == end2 [0x75250000] srcds [0xB10000]
Примеры:

1) Внедряем .dll через SourcePawn [GetProcAddress + вызов WINAPI LoadLibraryA]

Код:
#include <MemoryEx>

public void OnPluginStart()
{
    MemoryEx mem;

    mem.Init();

    mem.lib.InitModule("kernel32.dll");
  
    PrintToServer("ServerBase 0x%X size 0x%X kernel base 0x%X size 0x%X", GetServerDLLBase(), GetServerDLLSize(), mem.lib.GetBaseAddress("kernel32"), mem.lib.GetModuleSize("kernel32"));
    Pointer libAddr = mem.lib.GetProcAddress("kernel32", "LoadLibraryA");
    StartPrepSDKCall(SDKCall_Static);
    PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
    PrepSDKCall_SetAddress(libAddr);
    PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
    Handle h = EndPrepSDKCall();
    int baseDLL = SDKCall(h, "D:/CSS_HOOK.dll");

    PrintToServer("libaddr = 0x%X Base Address DLL = 0x%X ",libAddr, baseDLL);
    delete h;

}

Первая претензия была в том, что геймдату нужно изредко обновлять. Теперь мы просто ищем данное слово и "уничтожаем его"
Код:
#include <MemoryEx>

public void OnPluginStart()
{
    MemoryEx mem;
    mem.Init();
    mem.lib.InitModule("engine");
    Pointer pNoBots = mem.lib.FindString("server", "-nobots");

    if(pNoBots != nullptr)
    {
        mem.mem.SetAddr(pNoBots + PTR(0x01));
  
        for(int y = 0; y < 6; y++)    mem.mem.WriteByte(GetRandomInt(0x61, 0x7A), y);
    }

}
Но если посмотрим на претензию до конца, то видно, что если снять сжатие, было видно строки, что упрощает поимку плагина, что же делать? - Попробуем другой способ - через MemoryEx::FindPattern
Код:
#include <MemoryEx>

public void OnPluginStart()
{
    static int pattern[8] = {0x2D, 0x6E, 0x6F, 0x62, 0x6F, 0x74, 0x73, 0x00}; // `-nobots`;
    MemoryEx mem;

    if(mem.Init())
    {
        ModuleInfo server;
        server.base = mem.GetBaseAddress("server");
        server.size = mem.GetModuleSize("server");

        Pointer pStr = mem.FindPattern(server.base, server.size, pattern, sizeof(pattern), 0x01); // bypass `-`

        if(pStr != nullptr)
        {
            mem.SetAddr(pStr);
            for(int y = 0; y < 6; y++)    mem.WriteByte(GetRandomInt(0x61, 0x7A), y);
        }
    }
}
Требования
SourceMod 1.10+
  • 1579956901337.png
    1579956901337.png
    62.7 KB · Просмотры: 10
  • bandicam-2019-12-19-16-55-03-239.gif
    bandicam-2019-12-19-16-55-03-239.gif
    134.4 KB · Просмотры: 9
  • 1579957214032.png
    1579957214032.png
    6 KB · Просмотры: 9
  • 1579957221414.png
    1579957221414.png
    51.4 KB · Просмотры: 8
Автор
hirowatch
Скачивания
0
Просмотры
212
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок

Другие ресурсы пользователя hirowatch

Последние обновления

  1. Чтение Export/Import таблиц, фиксы багов, новые фишки и другое :)

    Версия 2.7 2.6 1) Удалены функции MemoryEx::Init / DynamicLibrary::Init /...
Сверху