Эта статья подойдёт для тех, кто пытается взломать/защитить приватные работы или столкнулся с отсутствием нормального апи

Сразу скажу, что вызвать функцию которой нет в секции .publics не получится, т.к. такую функцию можно считать "истинно локальной", вызвать которую можно разве что из-под более низкоуровневого яп чем сп. Функции может не быть там по 2-м причинам:

  1. Плагин собирался на версии компилятора ниже 1.7;
  2. Кто-то заморочился при сборке, поскольку компилятор явно был модифицирован.
Форварды, каллбеки и функции с модификатором public всегда находятся в .publics

Итак, допустим следующий код был собран на 1.10:
Код:
#include <sourcemod>

public void OnPluginStart()
{
    func("test");
}

void func(const char[] text)
{
    PrintToServer(text);
}
Запускаем и видим в консоли "test"

Теперь начинается какое-то волшебство:
  1. Открываем smxviewer (надеюсь, не надо разжёвывать как его собрать или хотя бы где взять уже собранный)
  2. Ищем имя функции. Если был указан модификатор public, то имя останется таким же, если нет, то к нему будет добавлен адрес в формате .адрес.имя1691429973777.png
  3. Набрасываем следующий код, где 1 - идентификатор функции из секции .publics
    Код:
    #include <sourcemod>
    
    public void OnPluginStart()
    {
        PrivateForward fwd = new PrivateForward(ET_Ignore, Param_String);
    
        // в 1.10 здесь будет предупреждение, которое можно проигнорировать, но в 1.11+
        // приведение к типу Function вызовет ошибку и плагин не соберётся
        fwd.AddFunction(FindPluginByFile("test.smx"), view_as<Function>(1));
    
        Call_StartForward(fwd);
        Call_PushString("test2");
        Call_Finish();
    }
    Запускаем и видим в консоли "test2"

    Версия для 1.11+ (используется эксплойт с не определённым размером массива):
    Код:
    #include <sourcemod>
    
    int ptr[1];
    Function func;
    
    void memset(int[] p, int off, int val)
    {
        p[off] = val;
    }
    
    Function getFunc(int f)
    {
        memset(ptr, 1, f);
        return func;
    }
    
    public void OnPluginStart()
    {
        PrivateForward fwd = new PrivateForward(ET_Ignore, Param_String);
        fwd.AddFunction(FindPluginByFile("test.smx"), getFunc(1));
    
        Call_StartForward(fwd);
        Call_PushString("test2");
        Call_Finish();
    }

Либо сделайте автоматическое получение идентификатора функции из имени через GetFunctionByName. Локальные имена придётся указывать в формате .адрес.имя

Единственное что 100% советую делать при использовании этой плюхи - выносить идентификаторы/имена функций в геймдату (см. след. страницу), ибо пересобирать решение после каждого обновления целевого плагина, которое может всё сломать, - не комильфо

А теперь приступим к "защите". У сторонних плагинов нет доступа к .data секции, поэтому если записывать туда данные, передавать в функцию и сверять их, то это можно считать как решение нашей головной боли
Код:
#include <sourcemod>

int protect;

public void OnPluginStart()
{
    protect = GetRandomInt(1, 100500);
    func(protect, "test")
}

void func(int data, const char[] text)
{
    if (data != protect)
        SetFailState("Гэндальф неодобрительно покачивает головой");
 
    PrintToServer(text);
}
Старайтесь не использовать эксплойт с не определённым размером массива, поскольку в этом случае у других плагинов будет доступ к .data секции (пример), либо соберите плагин с "истинно локальными" функциями используя компилятор по ссылке ниже

Если интересно, вот модификация последней версии из стабильной ветки (1.11-dev) с "истинно локальными" функциями: Releases · sourcepawn-publics