C/C++ [BinaryReader] IdentificationMessage (deserialisation)

Inscrit
2 Juillet 2015
Messages
41
Reactions
0
#1
Bonjour,
Je me suis inspiré du code de luax et de dofus 2.29 pour avoir mon BinaryReader, cependant je trouve des valeurs bizarres quand je deserialize le paquet IdentificationMessage.
voici le code de mon BinaryReader :
Code:
#ifndef BINARYREADER_H
#define BINARYREADER_H

#include <vector>
#include <deque>
#include <cstring>
#include <string>
#include <cmath>
#include "defines.h"

#include "int64.h"
#include "uint64.h"
class BinaryReader
{
public:
	BinaryReader(const char* buffer, int length);
	BinaryReader(const ByteArray buffer);
	BinaryReader(const std::deque<char> buffer);

	bool setPos(unsigned int pos);
	unsigned int getPos();
	int bytesAvailable();
	void reverseBytes(uint8_t* bytes, size_t count);
	void readBytes(uint8_t* bytes, size_t count);

	short readShort();
	unsigned short readUShort();
	int readInt();
	unsigned int readUInt();
	long readLong();
	unsigned long readULong();
	char readByte();
	unsigned char readUByte();
	ByteArray readBytes();
	ByteArray readBytes(int length);
	std::string readUTF();
	std::string readUTFBytes(unsigned int length);
	bool readBool();
	int readVarInt();
	unsigned int readVarUhInt();
	short readVarShort();
	unsigned short readVarUhShort();
	double readVarLong();
	double readVarUhLong();
	Int64 readInt64();
	UInt64 readUInt64();

private:
	ByteArray _buffer;
	unsigned int _pos;

	template<class T>
	void read(T &val);

	template<class T>
	void read(std::vector<T> &val);

	const int INT_SIZE = 32;
	const int SHORT_SIZE = 16;
	const int SHORT_MIN_VALUE = -32768;
	const int SHORT_MAX_VALUE = 32767;
	const int UNGISNED_SHORT_MAX_VALUE = 65536;
	const int CHUNK_BIT_SIZE = 7;
	const int MAX_ENCODING_LENGTH = std::ceil(INT_SIZE / CHUNK_BIT_SIZE);
	const unsigned char MASK_10000000 = 128;
	const unsigned char MASK_01111111 = 127;
};
BinaryReader.cpp
Code:
#include "binaryreader.h"
#include <stdexcept>

BinaryReader::BinaryReader(const char* buffer, int length) :
_buffer(buffer, buffer + length),
_pos(0)
{
}

BinaryReader::BinaryReader(const ByteArray buffer) :
_buffer(buffer),
_pos(0)
{
}

BinaryReader::BinaryReader(const std::deque<char> buffer) :
_pos(0)
{
	_buffer.reserve(buffer.size());
	std::copy(buffer.begin(), buffer.end(), std::back_inserter(_buffer));
}

bool BinaryReader::setPos(unsigned int pos)
{
	if (pos <= _buffer.size())
	{
		_pos = pos;
		return true;
	}

	return false;
}

unsigned int BinaryReader::getPos()
{
	return _pos;
}

int BinaryReader::bytesAvailable()
{
	return static_cast<int>(_buffer.size() - _pos);
}

void BinaryReader::reverseBytes(uint8_t* bytes, size_t count)
{
	for (size_t lo = 0, hi = count - 1; hi > lo; ++lo, --hi)
	{
		auto temp = bytes[hi];
		bytes[hi] = bytes[lo];
		bytes[lo] = temp;
	}
}

void BinaryReader::readBytes(uint8_t* bytes, size_t count)
{
	memcpy(bytes, &_buffer[_pos], count);
	_pos += count;
}

short BinaryReader::readShort()
{
	short value = 0;
	read(value);
	return value;
}

unsigned short BinaryReader::readUShort()
{
	unsigned short s = (unsigned char)_buffer[_pos] * 256 + (unsigned char)_buffer[_pos + 1];
	_pos += 2;//on lit 2 octets
	return s;
	/*unsigned short value = 0;
	read(value);
	return value;*/
}

int BinaryReader::readInt()
{
	int value = 0;
	read(value);
	return value;
}

unsigned int BinaryReader::readUInt()
{
	unsigned int value = 0;
	read(value);
	return value;
}

long BinaryReader::readLong()
{
	long value = 0;
	read(value);
	return value;
}

unsigned long BinaryReader::readULong()
{
	unsigned long value = 0;
	read(value);
	return value;
}

char BinaryReader::readByte()
{
	char value = _buffer[_pos];

	_pos++;
	return value;
}

unsigned char BinaryReader::readUByte()
{
	unsigned char value = static_cast<unsigned char>(_buffer[_pos]);

	_pos++;
	return value;
}

ByteArray BinaryReader::readBytes()
{
	int length = readUShort();

	ByteArray value;

	for (int i = 0; i < length; i++)
		value.push_back(_buffer[_pos + i]);

	value.push_back(0);
	_pos += length;
	return value;
}

ByteArray BinaryReader::readBytes(int length)
{
	ByteArray value;

	for (int i = 0; i < length; i++)
		value.push_back(_buffer[_pos + i]);

	value.push_back(0);
	_pos += length;
	return value;
}

std::string BinaryReader::readUTF()
{
	unsigned short len = readUShort();
	std::vector<char> data = readBytes(len);
	return std::string(data.begin(), data.end());
}

std::string BinaryReader::readUTFBytes(unsigned int length)
{
	ByteArray data = readBytes(length);
	return std::string(data.begin(), data.end());
}

bool BinaryReader::readBool()
{
	return readByte() == 1;
}

int BinaryReader::readVarInt()
{
	char byte;
	int value = 0;
	int offset = 0;
	bool hasNext;

	do
	{
		if (offset > INT_SIZE)
		{
			throw std::logic_error("Too much data");
		}

		byte = readByte();
		hasNext = ((byte & MASK_10000000) == MASK_10000000);

		if (offset > 0)
		{
			value = (value + ((byte & MASK_01111111) << offset));
		}
		else
		{
			value = (value + (byte & MASK_01111111));
		}

		offset = offset + CHUNK_BIT_SIZE;
	} while (hasNext);

	return value;
}

unsigned int BinaryReader::readVarUhInt()
{
	return static_cast<unsigned int>(readVarInt());
}

short BinaryReader::readVarShort()
{
	char byte;
	short value = 0;
	int offset = 0;
	bool hasNext;

	do
	{
		if (offset > SHORT_SIZE)
		{
			throw std::logic_error("Too much data");
		}

		byte = readByte();
		hasNext = ((byte & MASK_10000000) == MASK_10000000);

		if (offset > 0)
		{
			value = (value + ((byte & MASK_01111111) << offset));
		}
		else
		{
			value = (value + (byte & MASK_01111111));
		}

		offset = offset + CHUNK_BIT_SIZE;
	} while (hasNext);

	if (value > SHORT_MAX_VALUE)
	{
		value = static_cast<short>(value - UNGISNED_SHORT_MAX_VALUE);
	}

	return value;
}

unsigned short BinaryReader::readVarUhShort()
{
	return static_cast<unsigned short>(readVarShort());
}

double BinaryReader::readVarLong()
{
return readInt64().toNumber();
}

double BinaryReader::readVarUhLong()
{
return readUInt64().toNumber();
}

Int64 BinaryReader::readInt64()
{
unsigned char byte;
Int64 result;
unsigned int i = 0;

while (true)
{
byte = readUByte();

if (i == 28)
{
break;
}

if (byte >= MASK_10000000)
{
result.low = result.low | ((byte & MASK_01111111) << i);
}
else
{
result.low = result.low | (byte << i);
return result;
}

i += 7;
}

if (byte >= MASK_10000000)
{
byte = (byte & MASK_01111111);
result.low = result.low | (byte << i);
result.setHigh(static_cast<unsigned int>(byte >> 4));
}
else
{
result.low = result.low | (byte << i);
result.setHigh(static_cast<unsigned int>(byte >> 4));
return result;
}

while (true)
{
byte = readUByte();

if (i < 32)
{
if (byte >= MASK_10000000)
{
result.setHigh(result.getHigh() | (byte & MASK_01111111));
}
else
{
result.setHigh(result.getHigh() | (byte << i));
break;
}
}

i += 7;
}

return result;
}

UInt64 BinaryReader::readUInt64()
{
unsigned char byte;
UInt64 result;
unsigned int i = 0;

while (true)
{
byte = readUByte();

if (i == 28)
{
break;
}

if (byte >= MASK_10000000)
{
result.low = result.low | ((byte & MASK_01111111) << i);
}
else
{
result.low = result.low | (byte << i);
return result;
}

i += 7;
}

if (byte >= MASK_10000000)
{
byte = (byte & MASK_01111111);
result.low = result.low | (byte << i);
result.setHigh(static_cast<unsigned int>(byte >> 4));
}
else
{
result.low = result.low | (byte << i);
result.setHigh(static_cast<unsigned int>(byte >> 4));
return result;
}

while (true)
{
byte = readUByte();

if (i < 32)
{
if (byte >= MASK_10000000)
{
result.setHigh(result.getHigh() | (byte & MASK_01111111));
}
else
{
result.setHigh(result.getHigh() | (byte << i));
break;
}
}

i += 7;
}

return result;
}

template<class T>
void BinaryReader::read(T &val)
{
	readBytes(reinterpret_cast<uint8_t*>(&val), sizeof(T));
	reverseBytes(reinterpret_cast<uint8_t*>(&val), sizeof(T));
}

template<class T>
void BinaryReader::read(std::vector<T> &val)
{
	uint16_t size;
	read(size);
	val.resize(size);
	readBytes(reinterpret_cast<uint8_t*>(&val[0]), size);
}
voici comment je deserialize le paquet identificationMessage.
ma fonction de deserialisation du header
Code:
bool deserializePacket(ByteArray& byteArray)
{
	unsigned short _header=0;
	unsigned short _id=0;
	unsigned short _lengthType=0;
	unsigned int _length=0;
	BinaryReader binaryReader(byteArray);
	//compteur d'octets lus
	unsigned int readedBytesCount = 0;
	if (binaryReader.bytesAvailable() < sizeof(_header))
		return false;
	//on commence par lire le header du paquet (2 octets)

	_header = binaryReader.readUShort();
	//on extrait les données du header
	_id = getMessageId(_header);
	_lengthType = getMessageLengthType(_header);
	readedBytesCount += sizeof(_header);

	//on recupere la taille du message
	if (binaryReader.bytesAvailable() < _lengthType)
		return false;
	_length = getMessageLength(_lengthType, binaryReader);
	readedBytesCount += _lengthType;
	if (binaryReader.bytesAvailable() < _length)
	{
		return false;
	}
	ByteArray _data = binaryReader.readBytes(_length);
	readedBytesCount += _length;
	byteArray.erase(byteArray.begin(), byteArray.begin() + readedBytesCount);
	printf(PacketManager::instance()->getPacketName(_id));
	NetworkMessage* msg = PacketManager::instance()->getMessage(_id);
	if (msg != nullptr)
	{
		msg->setData(_header, _id, _lengthType, _length, _data);
		msg->deserialize();
	}
	else
	{
		std::cout << std::to_string(_id) << std::endl;
		std::cout << std::to_string(_lengthType) << std::endl;
	}
	printf("\n");
	return true;
}
La deserialisation du header marche bien, j'utilise une classe Factory (PacketManager) qui me crée des instances des paquets à la volée, ce qui me permet de deserializer les paquets dont l'id est connu.
Si on part du principe que je viens de recevoir un paquet IdentificationMessage, la portion de code :
Code:
NetworkMessage* msg = PacketManager::instance()->getMessage(_id);
	if (msg != nullptr)
	{
		msg->setData(_header, _id, _lengthType, _length, _data);
		msg->deserialize();
	}
va appeler la methode deserialize de IdentificationMessage qui hérite de NetworkMessage:
Code:
void IdentificationMessage::deserialize()
{
	Poco::Logger::root().information("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
	Poco::Logger::root().information("nom : " + std::string(this->_name));
	Poco::Logger::root().information("id : " + std::to_string(this->_id));
	Poco::Logger::root().information("lengthType : " + std::to_string(this->_lengthType));
	Poco::Logger::root().information("length Data : " + std::to_string(this->_length));
	Poco::Logger::root().information("DATA ..................");
	BinaryReader binaryReader(_data);
	char _loc7_= 0;
	uint8 _loc8_ = 0;
	char loc2 = binaryReader.readByte();
	this->autoconnect = BooleanByteWrapper::getFlag(loc2, 0);
	this->useCertificate = BooleanByteWrapper::getFlag(loc2, 1);
	this->useLoginToken = BooleanByteWrapper::getFlag(loc2, 2);
	this->version.deserialize(binaryReader);
	lang = binaryReader.readUTF();
	int credentialsLen = binaryReader.readVarInt();
	credentials = binaryReader.readBytes(credentialsLen);
	serverId = binaryReader.readShort();
	sessionOptionalSalt = binaryReader.readVarLong();
	unsigned int failedAttemptsLen = binaryReader.readUShort();
	for (int i = 0; i < failedAttemptsLen; ++i)
	{
		unsigned short attempt = binaryReader.readVarUhShort();
		failedAttempts.push_back(attempt);
	}
	Poco::Logger::root().information("langue : " + lang);
	Poco::Logger::root().information("server id : " + std::to_string(serverId));
	Poco::Logger::root().information("autoConnect : " + std::to_string(autoconnect));
	Poco::Logger::root().information("useCertificate : " + std::to_string(useCertificate));
	Poco::Logger::root().information("useLoginToken : " + std::to_string(useLoginToken));
	std::string credentialS(credentials.begin(),credentials.end());
	Poco::Logger::root().information("credentials : " + credentialS);
	Poco::Logger::root().information("sessionOptionalSalt : " + std::to_string(sessionOptionalSalt));
}
pour info voici les différents types des attributs :
Code:
        VersionExtended version;

	std::string lang;
	std::vector<char> credentials;
	short serverId;
	bool autoconnect = false;
	bool useCertificate = false;
	bool useLoginToken = false;
	double sessionOptionalSalt;
	std::vector<unsigned short> failedAttempts;
Dnas cette méthode, les données récupérées sont loggées dans un fichier, dont voici le contenu (juste pour ce message)
Code:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
nom : IdentificationMessage
id : 4
lengthType : 2
length Data : 279
DATA ..................
VersionExtended: deserialize
Version: deserialize
major : 2
minor : 29
release : 1
revision : 141
patch : 1
install : 1
technology : 1
server id : 0
autoConnect : 0
useCertificate : 1
useLoginToken : 0
langue : fr
Les données m'ont l'air ok jusqu'a langue...Mais à partir de la j'ai des valeurs bizarre que je ne peux pas copier coller...Elles n'apparaissent pas dans le spoiler ci-dessus.
Je vous mets donc une screenshot de mon fichier log pour que vous vous rendiez compte.
dans les logs, on aperçoit "langue : frNULL" le null ne serait-il pas un caractere "\0"?
Est ce que ce sont des valeurs binaires?
Avez vous deja rencontré de telles valeurs?
Comment dois je faire pour extraire les Number as3? j'ai vu qu'ils utilisent des classes specifiques binary64 Int64 Uint64. Mais n'y a-t-il pas d'autres solutions?
 
Inscrit
16 Mars 2014
Messages
214
Reactions
30
#2
Pour voir tes valeurs "bizarre" utilise HxD ou n'importe quel éditeur Hex tu aura une vue plus subjective, et sinon pour les "credetentials" (nom de compte, mot de passe) ne peuvent pas être récupérer directement en clair via le message fin du moins il me semble
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#4
Les identifiants sont cryptés en RSA modifié quelques peu par Ankama, je te redirige vers les sources pour en savoir plus.

Code:
case msg is HelloConnectMessage:
               hcmsg = HelloConnectMessage(msg);
               AuthentificationManager.getInstance().setPublicKey(hcmsg.key);
               AuthentificationManager.getInstance().setSalt(hcmsg.salt);
               AuthentificationManager.getInstance().initAESKey();
               iMsg = AuthentificationManager.getInstance().getIdentificationMessage();
               _log.info("Current version : " + iMsg.version.major + "." + iMsg.version.minor + "." + iMsg.version.release + "." + iMsg.version.revision + "." + iMsg.version.patch);
               dhf = Kernel.getWorker().getFrame(DisconnectionHandlerFrame) as DisconnectionHandlerFrame;
               time = Math.round(getTimer() / 1000);
               elapsedTimesSinceConnectionFail = new Vector.<uint>();
               failureTimes = StoreDataManager.getInstance().getData(Constants.DATASTORE_MODULE_DEBUG,"connection_fail_times");
               if(failureTimes)
               {
                  i = 0;
                  while(i < failureTimes.length)
                  {
                     elapsedSeconds = time - failureTimes[i];
                     if(elapsedSeconds <= 3600)
                     {
                        elapsedTimesSinceConnectionFail[i] = elapsedSeconds;
                     }
                     i++;
                  }
                  dhf.resetConnectionAttempts();
               }
               iMsg.failedAttempts = elapsedTimesSinceConnectionFail;
               ConnectionsHandler.getConnection().send(iMsg);
               KernelEventsManager.getInstance().processCallback(HookList.ConnectionTimerStart);
               TimeManager.getInstance().reset();
               return true;
 
Dernière édition:
Inscrit
16 Mars 2014
Messages
214
Reactions
30
#5
Après sa dépens ce que tu cherche à faire mais si c'est pour un émulateur il existe un moyen de récupérer les infos du compte sans ce prendre la tête
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#6
Enfin si tu penses à la technique de BiM, cela nécessite la modification du client mais je ne pense pas qu'on puisse passer l'identification sans.
 
Inscrit
2 Juillet 2015
Messages
41
Reactions
0
#7
Merci pour toutes vos réponses!
Je teste et je vous dis ce qu'il en ressort!
Merci encore pour votre aide, ça aide à aller vite!
 
Haut Bas