Информация Гайд Работа с RakNet хуками с помощью SAMPFUNCS

Статус
В этой теме нельзя размещать новые ответы.
[UPPERCASE]Achtung[/UPPERCASE] Написано дебилом для дебилов, но если что снизу можно задать вопрос [UPPERCASE]Achtung[/UPPERCASE]

Введение
В данном уроке будет разбираться работа с RakNet хуками через CLEO с помощью SAMPFUNCS.

RakNet является сетевым движком SAMP'а. Все данные, которые взаимодействуют в сети, хранятся в BitStream (битстрим) - структура, которая хранит данные как последовательность битов.
В SAMP имеется 2 вида для обмена информацией между клиентом и сервером - Packet и RPC.


> Packet
Packet (далее - пакет) - сообщение от сервера/клиента, в BitStream'е которого хранится сначала ид, а далее идут различные данные. Есть и исключения - некоторые пакеты не имеют данных, они используются как оповещение (к примеру, при разрыве соединения от сервера).
В данном подразделе мы разберем способы их чтения и отправки.

Перехват

Перехват(с англ. "hook" (хук)) - операция при которой основной адрес функции меняется на собственный => возможность чтения/подмены данных.

Пакет может быть двух видов: входящий, исходящий.
Входящие - отправляемые от сервера (сервер-клиент), исходящие - отправляемые серверу (клиент-сервер).

Алгоритм чтения:
  • Ищем необходимый ID (с помощью опкода opcodes:0be5);
  • Получаем BitStream (с помощью того же опкода opcodes:0be5);
  • Читаем BitStream (первый байт (8 битов) можно опустить опкодом opcodes:0beb, т.к. он является идом пакета);
  • Завершаем работу с текущими данными используя опкод opcodes:0be0.

Перехват входящих
Для перехвата входящих пакетов используется опкод opcodes:0be4.
Благодаря данному перехвату мы сможем отредактировать/прочитать данные, которые присылается к нам.

Данный код будет выводить активный трейлер (который закреплен за автомобилем игрока) как маркер на карту:
CLEO:
{$CLEO}
{$INCLUDE SF}

0001: wait 0 ms

while not SAMP.Available()
    wait 400
end

7@ = 0 // Обнуляем переменную(нет необходимости, сделал для наглядности)

0BE4: raknet setup_incoming_packet_hook @in_packet // Установка хука

while true
    wait 0
    // Переменные, используемые в хуке взаимосвязаны, поэтому если в теле хука была изменена переменная, то и в данной области она тоже будет изменена. Имейте это в виду.

    if 7@ <> 0 // Если маркер был создан ранее
    then
        if not 0 = SAMP.GetActorHandleByPlayerID(2@) // Если игрок, приславший нам последний пакет о синхронизации трейлера, неактивен, то удаляем маркер с карты
        then
            0164: disable_marker 7@ // Уничтожаем маркер
            7@ = 0 // Обнуляем переменную
        end
    end
end

:in_packet
0BE5: raknet 0@ = get_hook_param PARAM_PACKETID // Получаем ИД пакета
if 0@ == PACKET_TRAILER_SYNC // Сравниваем
then
    0BE5: raknet 1@ = get_hook_param PARAM_BITSTREAM // Получаем битстрим
    0BEB: raknet bit_stream 1@ ignore_bits 8 // packetId // 1 байт - ИД пакета - пропускаем

    0BE7: raknet 2@ = bit_stream_read 1@ type BS_TYPE_SHORT // playerId // Читаем ИД игрока, приславшего нам пакет
    0BE7: raknet 3@ = bit_stream_read 1@ type BS_TYPE_SHORT // trailerId // ИД трейлера, который он везет
    0BE7: raknet 4@ = bit_stream_read 1@ type BS_TYPE_FLOAT // pos[0] // Позиция трейлера по оси X
    0BE7: raknet 5@ = bit_stream_read 1@ type BS_TYPE_FLOAT // pos[1] // ... по оси Y
    0BE7: raknet 6@ = bit_stream_read 1@ type BS_TYPE_FLOAT // pos[2] // ... по оси Z
    // Также можно прочитать данные дальше, но нам они не нужны :)

    if 7@ <> 0 // Если маркер был создан ранее
    then
        0164: disable_marker 7@ // то удаляем его, чтобы карта не заполонилась значками
        7@ = 0 // Обнуляем(нет необходимости здесь его обнулять, но всё ж)
    end
    02A8: 7@ = create_marker 51 at 4@ 5@ 6@ // Создаем
end
0BE0: raknet hook_ret true // Принимаем пакет. Если поставить значение false, то данные от сервера не будут приняты.

Перехват исходящих
Для перехвата исходящих пакетов используется опкод opcodes:0be2.
Благодаря данному перехвату мы сможем отредактировать/прочитать данные, которые отправляются от нас.

В данном коде будет происходить перезапись исходящих от нас данных, а именно - синхронизация пешком. Для всех мы будем находиться глубоко под землей:
CLEO:
{$CLEO}
{$INCLUDE SF}

0001: wait 0 ms

while not SAMP.Available()
    wait 400
end

0BE2: raknet setup_outcoming_packet_hook @out_packet // Подготавливаем хук

0BDE: pause_thread 0 // Бесконечный цикл нам не нужен, поэтому просто поставим скрипт на "паузу". Хуки, вызовы команды и т.п., что не требует постоянной обработки, будут работать в это время.

:out_packet
0BE5: raknet 0@ = get_hook_param PARAM_PACKETID // Получаем ИД пакета
if 0@ == PACKET_PLAYER_SYNC // Сравниваем
then
    0BE5: raknet 1@ = get_hook_param PARAM_BITSTREAM // Получаем битстрим

    0BF3: raknet 2@ = bit_stream 1@ get_data_ptr // Получаем указатель на содержимое битстрима
    0C0D: struct 2@ offset 15 size 4 = -90.0 // в данные битстрима установим значение -90.0. Это будет координата Z в синхронизации.

    // Ещё один из типов перезаписи
    /*
    0AC8: alloc 2@ 69 // sizeof(onFootData) + packetId // выделяем память для хранения данных битстрима
    0BE8: raknet bit_stream 1@ read_array 2@ size 69 // записываем в выделенную память(первый байт - ид пакета, всё остальное - синхронизация игрока(68 байт))

    0C0D: struct 2@ offset 15 size 4 = -90.0 // в данные битстрима установим значение -90.0. Это будет координата Z в синхронизации.

    0BEA: raknet bit_stream 1@ reset_write_pointer // сбрасываем указатель записи в битстриме
    0B40: raknet bit_stream 1@ write 2@ type BS_TYPE_ARRAY size 69 // записываем новые данные

    0AC9: free 2@ // освобождаем, т.к. выделенная память больше не нужна, все данные уже хранятся в перезаписанном битстриме
    */
end
0BE0: raknet hook_ret true // отправляем пакет, false - не отправлять

Эмуляция
Для того, чтобы сэмулировать входящие пакеты, применяется опкод opcodes:0bf7.


> RPC
RPC - то же, что и пакет, но с первого байта сразу записываются данные (у пакетов записывается их ид).

Перехват
RPC так же бывает двух направлений: входящий, исходящий.
Алгоритм чтения такой же, как и у пакетов, но при этом первый байт не нужно пропускать.

Перехват входящих
Для перехвата входящих RPC используется опкод opcodes:0be3.

Данный код будет выводить сообщения о подключившихся/отключившихся игроках:
CLEO:
{$CLEO}
{$INCLUDE SF}

0001: wait 0 ms

while not SAMP.Available()
    wait 400
end

0BE3: raknet setup_incoming_rpc_hook @in_rpc // подготавливаем хук

0BDE: pause_thread 0 // Бесконечный цикл нам не нужен, поэтому просто поставим скрипт на "паузу". Хуки, вызовы команды и т.п. будут работать в это время

:in_rpc
0BE5: raknet 0@ = get_hook_param PARAM_PACKETID // Получаем ИД RPC
if or
    0@ == RPC_SCRSERVERJOIN // сверяем с необходимым ИДом
    0@ == RPC_SCRSERVERQUIT // ...
then
    0BE5: raknet 1@ = get_hook_param PARAM_BITSTREAM // Получаем битстрим

    if 0@ == RPC_SCRSERVERJOIN
    then
        // RPC_SCRSERVERJOIN
        0BE7: raknet 2@ = bit_stream_read 1@ type BS_TYPE_SHORT // ид подключившегося игрока
        0BE7: raknet 3@ = bit_stream_read 1@ type BS_TYPE_INT // цвет никнейма
        0BE7: raknet 4@ = bit_stream_read 1@ type BS_TYPE_BYTE // игрок NPC(true - да, false - нет)
        0BE7: raknet 5@ = bit_stream_read 1@ type BS_TYPE_BYTE // длина ника

        0AC8: 6@ = allocate_memory_size 25 // буфер
        0BE8: raknet bit_stream 1@ read_array 6@ size 5@ // копируем никнейм с указанной длиной в буфер
        0C1E: array 6@ element 5@ el_size 1 = 0 // обрезаем буфер нулевым символом(т.к. нулевой символ - конец строки), чтобы при чтении не попадало лишних символов
        0AF8: samp add_message_to_chat "%s[%d] подключился на сервер." color -1 params 6@ 2@ // выводим сообщение в чат
        0AC9: free_allocated_memory 6@
    else
        // RPC_SCRSERVERQUIT
        0BE7: raknet 2@ = bit_stream_read 1@ type BS_TYPE_SHORT // ид отключившегося игрока
        0BE7: raknet 3@ = bit_stream_read 1@ type BS_TYPE_BYTE // причина отключения
        0AF8: samp add_message_to_chat "Игрок с ИДом %d отключился от сервера. Код причины: %d" color -1 params 2@ 3@ // ...
    end
end
0BE0: raknet hook_ret true // принимаем RPC, false - не принимать

Перехват исходящих
Для перехвата исходящих RPC используется опкод opcodes:0be1.

Данный код будет выводить сообщение о введенной и отправленной вами команде/текста:
CLEO:
{$CLEO}
{$INCLUDE SF}

0001: wait 0 ms

while not SAMP.Available()
    wait 400
end

0BE1: raknet setup_outcoming_rpc_hook @out_rpc // подготавливаем хук

0BDE: pause_thread 0 // Бесконечный цикл нам не нужен, поэтому просто поставим скрипт на "паузу". Хуки, вызовы команды и т.п. будут работать в это время

:out_rpc
0BE5: raknet 0@ = get_hook_param PARAM_PACKETID // Получаем ИД RPC
if or
    0@ == RPC_CHAT // сверяем с необходимым ИДом
    0@ == RPC_SERVERCOMMAND // ...
then
    0BE5: raknet 1@ = get_hook_param PARAM_BITSTREAM // Получаем битстрим

    0AC8: 3@ = allocate_memory_size 145 // подготавливаем буфер для хранения сообщения/команды

    if 0@ == RPC_CHAT
    then
        // RPC_CHAT
        0BE7: raknet 2@ = bit_stream_read 1@ type BS_TYPE_BYTE // получаем длину отправленного сообщения

        0BE8: raknet bit_stream 1@ read_array 3@ size 2@ // копируем сообщение с указанной длиной из битстрима в буфер
        0C1E: array 3@ element 2@ el_size 1 = 0 // завершаем буфер нулевым символом, чтобы при чтении не было ненужных символов в конце строки
        0AF8: samp add_message_to_chat "Я вангую, что ты сейчас напишешь: \"%s\"" color -1 3@ // Отправляем сообщение в чат
    else
        // RPC_SERVERCOMMAND
        0BE7: raknet 2@ = bit_stream_read 1@ type BS_TYPE_INT // получаем длину отправленной команды

        0BE8: raknet bit_stream 1@ read_array 3@ size 2@ // копируем команду с указанной длиной из битстрима в буфер
        0C1E: array 3@ element 2@ el_size 1 = 0 // завершаем буфер нулевым символом, чтобы при чтении не было ненужных символов в конце строки
        0AF8: samp add_message_to_chat "Я вангую, что ты сейчас введешь команду: \"%s\"" color -1 3@ // Отправляем сообщение в чат
    end

    0AC9: free_allocated_memory 3@ // Буфер больше не нужен для текущей операции
end
0BE0: raknet hook_ret true // отправляем RPC, false - не отправляем

Эмуляция
Для того, чтобы сэмулировать входящие RPC, применяется опкод opcodes:0bf6.
 
Последнее редактирование:

itsLegend

Фонд борьбы за жуков 🐞
Автор темы
Администратор
2,695
1,447
Я и не троллю.
Если ты про структуру пакетов, то вот здесь есть список, не знаю насколько сильно устарел, но по крайней мере onFoot сходится.
В примере 15 потому что 1 байт - ид пакета, если чо. В структуре это 14.
 
Статус
В этой теме нельзя размещать новые ответы.

Похожие темы

    • Закреплено
    • Статья
    Ответы
    197
    Просмотры
    674K
  1. У
    • Закрыта
      • Нравится
    Ответы
    4
    Просмотры
    3K
    CLEO
    Удалённый пользователь 144706
    У