Форум работает в тестовом режиме. Все данные были перенесены со старого сайта 2018 года. Некоторая информация может быть недоступна, например вложения или хайды. Просьба сообщать о данных случаях через функционал "Жалоба", прямо под постом, где отсуствуют данные из хайда или проблемы с вложением.
Могут быть проблемы в "выкидыванием" с форума (слетевшей авторизацией). Нужно собрать статистику таких случаев.
Есть Тема, куда можете сообщить о проблемах с сайтом либо просто передать привет.

Packet helper

rsd

Рег
3 Дек 2015
Сообщения
174
Реакции
0
Видел, много раз поднималась тема о получении инфы, которую адреналин не дает (в частности разбор системных сообщений), выкладываю для тех, кто пишет что то немного посложнее возврата на спот.

Описание типов:

TL2PacketValueType = (
lpvNone,
lpvString,
lpvByte,
lpvWord,
lpvDWord,
lpvInteger,
lpvDouble,
lpvInt64,
lpvList
);

TL2PacketValue = record
public
name: string;
valueType: TL2PacketValueType;
hexValue: string;
stringValue: string;
byteValue: byte;
wordValue: word;
integerValue: integer;
doubleValue: double;
int64Value: int64;
listValue: array of TL2Packetvalue;
end;

TL2Packet = record
public
name: string;
contents: array of TL2PacketValue;
//structPath - путь к ini файлу с описанием протокола. в аттаче лежат под хроники c6-god из последнего phx.
procedure fetchFromMemory(const structPath: string; id, id2: cardinal; data: pointer; size: word; isClentPacket: boolean = false);
function valueWithName(const name: string; desiredType: TL2PacketValueType = lpvNone): TL2PacketValue;
end;

Как с этим работать?
Во первых, нужна точная структура пакета, который вы хотите разобрать.
Многие сервера используют нестандартный протокол, который знают только админы :lol:
Поэтому, очень часто, структуру придется восстанавливать самостоятельно.

Небольшой пример, вывода всей инфы о пакете:

uses SysUtils, PacketHelper;

procedure OnPacket(ID, ID2: Cardinal; Data: Pointer; Size: Word);
var
charName : String;
character: TL2Live;
i, j: cardinal;
packet: TL2Packet;
begin
case intToHex(id, 2) of
'62' :
begin
packet.fetchFromMemory(script.path + 'PacketsHighFive.ini', id, id2, data, size);
print('======');
print('@' + packet.name);
for i:= 0 to high(packet.contents) do
begin

if packet.contents.valueType = lpvList then
begin
for j:= 0 to high(packet.contents.listValue) do
begin
print(format('%s[%d] : %s', [packet.contents.listValue[j].name, j, packet.contents.listValue[j].stringValue]));
end;
end
else
begin
print(format('%s : %s', [packet.contents.name, packet.contents.stringValue]));
end;

end;
end;
end;

end;

begin
delay(-1);
end.

Вывод:
b4993a3a70.png


Теперь, разбор на примере вывода каунта пикапнутой адены:
вывод всего пакета:
2.png

uses SysUtils, PacketHelper;

procedure OnPacket(ID, ID2: Cardinal; Data: Pointer; Size: Word);
var
charName : String;
character: TL2Live;
i, j, amnt: cardinal;
packet: TL2Packet;
begin
case intToHex(id, 2) of
'62' :
begin
packet.fetchFromMemory(script.path + 'PacketsHighFive.ini', id, id2, data, size);

//получаем id сообщения
if packet.valueWithName('MsgID:Get.MsgID').integerValue = 28 then
begin
//тип 6 - amnt, скорее всего 4 байта без знака
//
amnt:= pcardinal(pchar(packet.valueWithName('data').listValue[0].stringValue))^;
print(amnt);
end;

end;
end;

end;

begin
delay(-1);
end.

Вывод:
3.png
 

Вложения

  • packetHelper.rar
    91.7 KB · Просмотры: 260
то что нужно! Спасибо! Как раз искал недавно способ парсинга ГМ анонсов :)
 
Пользуйтесь с осторожностью, можно получить автобан на некоторых серверах. А если еще и криво что-то там написать, то бот будет вылетать\виснуть.
 
@Ivanius, какой еще автобан, если кроме анализа данная фича ничего не делает?
 
@rsd, Да скниффер именно так и работал и банили за него. А я говорю абсолютно серьзено, не раз встречал сервера где вроде и ломаный работает, а как только начинаешь играться с пакетами и проверять - сразу автобан, благо по айпи.
 
Ivanius написал(а):
начинаешь играться с пакетами и проверять - сразу автобан, благо по айпи.
если отправлять, то конечно забанят.
но предложенное расширение вовсе не для этого.


Krickt написал(а):
хм, но ведь за сниффер адрика тоже банили на некоторых серверах, что-то помню такое.
что то из разряда фантастики, скорее всего банили за факт присутствия программы которая врядли обладала какой то защитой от обнаружения, а не за то, что она делала.


если не баняться другие функции бота, то с чего бы onpacket палился?

вот с sendtoserver опасно играться, да, по понятным причинам.
 
Я так понимаю,что данный скрипт прокатит только для серверов со стандартной шифрацией,которых нынче днем с огнем не найдешь,тогда смысл в чем?
 
@vs23, Работает много где, адреналин "расшифровывает".
 
трейд между чарами возможно заснифить через этот скриптик?
 
@battleground,

Да, любое действие в игре, т.к. все это реализовано через пакеты
 
узнаю я пакет трейда, я смогу его послать через сенд пакет ? или нужно переводить в другую форму?
 
может кто подсказать как запустить скрипт? закинуть в папку с ботом Scripthelper, изменить в нем, строки что описывают классы, а потом сохранить в формате .pcu, а потом запустить скрипт для получения инфы о пакете? Но в адрике при этом раскладе пишет, Compile version is different.
 
@battleground, Думаю вот так и положить с ним в одну папку это! PacketsHighFive.ini ,или какие у тебя хроники
unit PacketHelper;

interface

uses SysUtils, Classes;

// //
// Описание //
// //
// Типы данных используемые в пакетах: //
// c: Byte (1 байт) //
// h: Word (2 байта) //
// d: DWord (4 байта) //
// f: Double (8 байт) //
// q: Int64 (8 байт целое) //
// s: String //
// i: DWord (4 байта) - отведен специально для ItemID //
// l: DWord (4 байта) - отведен специально для SkillID //
// o: DWord (4 байта) - отведен специально для ObjectID и CharID //
// //
// b: Array of Byte - массив байт, записывается в виде: b(Key:0016), где //
// Key - описание; //
// 0016 - размер массива; //
// В пакетах Kamael возможна ситуация, когда размер массива задается //
// в предидущем куске пакета, пример: //
// 09=RequestSetPledgeCrest:d(CrestSize)b(Data:Back) //
// т.е. размер будет идти в CrestSize, //
// для этого я делаю b(Data:Back) //
// Back - означает что размер нужно прочитать из предидущего куска пакета. //
// //
// Во многих пакетах, очень часто встречаются циклические списки, //
// пример: //
// 18=StatusUpdate:eek:(ObjectID)d(ListSize:Loop.1.2)d(ID)d(Value) //
// //
// здесь в куске d(ListSize:Loop.0001.0002) //
// ListSize - количество повторов цикла //
// Loop - означает что будет цикл //
// 0001 - элемент пакета с которого начинать цикл //
// 0002 - сколько элементов циклить //
// //
// т.е. элементы d(ID) и d(Value) будут повторятся ListSize количество раз. //
// //
/////////////////////////////////////////////////////////////////////////////////
type
TSettings = packed record
private
fFile: string;
public
procedure SetFile(const Name: string);
procedure Save(const Section, Key, Data: string); overload;
procedure Save(const Section, Key: string; Data: Integer); overload;
function Load(const Section, Key: string; DefData: string = ''): string; overload;
function Load(const Section, Key: string; DefData: integer = 0) : integer; overload;
end;

TL2PacketValueType = (
lpvNone,
lpvString,
lpvByte,
lpvWord,
lpvDWord,
lpvInteger,
lpvDouble,
lpvInt64,
lpvList
);

TL2PacketValue = record
public
name: string;
valueType: TL2PacketValueType;
hexValue: string;
stringValue: string;
byteValue: byte;
wordValue: word;
integerValue: integer;
doubleValue: double;
int64Value: int64;
listValue: array of TL2Packetvalue;
end;

TL2Packet = record
private
function fetchValueFromMemory(const value: string; data: pointer; var offset: word): TL2PacketValue;
public
name: string;
contents: array of TL2PacketValue;
procedure fetchFromMemory(const structPath: string; id, id2: cardinal; data: pointer; size: word; isClentPacket: boolean = false);
function valueWithName(const name: string; desiredType: TL2PacketValueType = lpvNone): TL2PacketValue;
end;

implementation

var buf: array [0..8192] of Byte;

procedure TSettings.SetFile(const Name: string);
begin
fFile := Name;
end;

function GetPrivateProfileIntW(lpAppName, lpKeyName: PChar; nDefault: Integer; lpFileName: PChar): Integer; stdcall; external 'Kernel32.dll';
function GetPrivateProfileStringW(lpAppName, lpKeyName, lpDefault: PWideChar; lpReturnedString: Pointer; nSize: DWORD; lpFileName: PWideChar): DWORD; stdcall; external 'Kernel32.dll';
function WritePrivateProfileStringW(lpAppName, lpKeyName, lpString, lpFileName: PChar): Boolean; stdcall; external 'Kernel32.dll';

procedure TSettings.Save(const Section, Key, Data: string);
begin
WritePrivateProfileStringW(PChar(Section), PChar(Key), PChar(Data), PChar(fFile));
end;

procedure TSettings.Save(const Section, Key: string; Data: Integer);
begin
Save(Section, Key, IntToStr(Data));
end;

function TSettings.Load(const Section, Key: string; DefData: string = ''): string;
begin
GetPrivateProfileStringW(PChar(Section), PChar(Key), PChar(DefData), @buf, 8192, PChar(fFile));
Result := PChar(@buf);
end;

function TSettings.Load(const Section, Key: string; DefData: integer = 0): Integer;
begin
Result := GetPrivateProfileIntW(PChar(Section), PChar(Key), DefData, PChar(fFile));
end;

function TL2Packet.fetchValueFromMemory: TL2PacketValue;
begin
result.name:= copy(value, 3, length(value) - 2);
case value[1] of
'c':
begin
result.valueType:= lpvByte;
result.byteValue:= pbyte(pointer(integer(data) + offset))^;
result.stringValue:= result.byteValue.toString;
result.hexValue:= memToHex(pointer(integer(data) + offset)^, 1);
offset:= offset + 1;
end;
'h':
begin
result.valueType:= lpvWord;
result.wordValue:= pword(pointer(integer(data) + offset))^;
result.stringValue:= result.wordValue.toString;
result.hexValue:= memToHex(pointer(integer(data) + offset)^, 2);
offset:= offset + 2;
end;
'd', 'i', 'l', 'o':
begin
result.valueType:= lpvInteger;
result.integerValue:= pinteger(pointer(integer(data) + offset))^;
result.stringValue:= result.integerValue.toString;
result.hexValue:= memToHex(pointer(integer(data) + offset)^, 4);
offset:= offset + 4;
end;
'f':
begin
result.valueType:= lpvDouble;
result.doubleValue:= pdouble(pointer(integer(data) + offset))^;
result.stringValue:= result.doubleValue.toString;
result.hexValue:= memToHex(pointer(integer(data) + offset)^, 8);
offset:= offset + 8;
end;
'q':
begin
result.valueType:= lpvInt64;
result.int64Value:= pint64(pointer(integer(data) + offset))^;
result.stringValue:= result.int64Value.toString;
result.hexValue:= memToHex(pointer(integer(data) + offset)^, 8);
offset:= offset + 8;
end;
's':
begin
result.valueType:= lpvString;
result.stringValue:= string(pchar(pointer(integer(data) + offset)));
result.hexValue:= memToHex(pointer(integer(data) + offset)^, (length(result.stringValue) + 1) * 2);
offset:= offset + (length(result.stringValue) + 1) * 2;
end;
end;
end;

procedure TL2Packet.fetchFromMemory;
var
struct, temp, idStr: string;
ini: TSettings;
valuesCount, listLoopsCount, listSize, listStartFrom: cardinal;
i, j, k: cardinal;
offset: word;
values: TStringList;
listInfo: TL2PacketValue;
begin
ini.setFile(structPath);

idStr:= intToHex(id, 2);

if id2 > 0 then
idStr:= idStr + intToHex(id2, 2);

if isClentPacket then
struct:= ini.load('client', idStr, '')
else
struct:= ini.load('server', idStr, '');

if struct = '' then
exit;

name:= copy(struct, 1, pos(':', struct) - 1);
delete(struct, 1, pos(':', struct));
struct:= stringReplace(struct, ')', #13#10, [rfReplaceAll, rfIgnoreCase]);
values:= TStringList.create;
values.text:= struct;

valuesCount:= 0;
for i:= 0 to values.count - 1 do
if pos('Loop', values) = 0 then
inc(valuesCount);

offset:= 0;
i:= 0;
setLength(contents, valuesCount);
while (size > offset) and (i < valuesCount) do
begin

if pos('Loop', values) > 0 then
begin
listInfo:= fetchValueFromMemory(values, data, offset);
listLoopsCount:= strToInt(listInfo.stringValue);
temp:= copy(values, 3, length(values) - 2);
delete(temp, 1, pos('.', temp));

listStartFrom:= strToInt(copy(temp, 1, pos('.', temp) - 1));

delete(temp, 1, pos('.', temp));

listSize:= strToInt(temp);
values.delete(i);

for j:= 0 to listSize - 1 do
begin
setLength(contents[i + j].listValue, listLoopsCount);
contents[i + j].name:= copy(values[i + j], 3, length(values[i + j]) - 2);
contents[i + j].valueType:= lpvList;
contents[i + j].stringValue:= format('list[%d]', [listLoopsCount]);
end;

if listLoopsCount > 0 then
for j:= 0 to listLoopsCount - 1 do
for k:= 0 to listSize - 1 do
contents[i + k].listValue[j]:= fetchValueFromMemory(values[i + k], data, offset);

inc(i, listSize);

end
else
begin
contents:= fetchValueFromMemory(values, data, offset);
inc(i);
end;

end;
values.free;
end;

function TL2Packet.valueWithName: TL2Packetvalue;
var
i: cardinal;
begin
for i:= 0 to high(contents) do
if ansiCompareText(contents.name, name) = 0 then
begin
if desiredType = lpvNone then
begin
result:= contents;
exit;
end
else
if contents.valueType = desiredType then
begin
result:= contents;
exit;
end;
end;
end;

begin
end.
 
uses SysUtils, PacketHelper;

procedure OnPacket(ID, ID2: Cardinal; Data: Pointer; Size: Word);
var
charName : String;
character: TL2Live;
i, j, amnt: cardinal;
packet: TL2Packet;
begin
case intToHex(id, 2) of
'62' :
begin
packet.fetchFromMemory(script.path + 'packetsInterlude.ini', id, id2, data, size);

//получаем id сообщения
if packet.valueWithName('MsgID:Get.MsgID').integerValue = 28 then
begin
//тип 6 - amnt, скорее всего 4 байта без знака
//
amnt:= pcardinal(pchar(packet.valueWithName('data').listValue[0].stringValue))^;
print(amnt);
end;

end;
end;

end;

begin
delay(-1);
end.

при попытке запуска этого кода, или выше, выдает ошибку Incorrect compiled script version. у меня packetsInterlude.ini, изменил в скрипте это название, опис класов закинул в папку с ботом, в тхт формате и в pcu формате, название PacketHelper, в чем может быть проблема?
 
Назад
Сверху