Incompréhension du paquet

Inscrit
23 Decembre 2016
Messages
6
Reactions
0
#1
Bonjour à tous,
J'ai commencé il y a trés peu de temps l'analyse des paquets de D2 afin de créer si cela se concrétise un bot full socket (sûrement en c++).
Cependant, je n'arrive pas à comprendre la structure des paquets : Exemple
0D 75 36 00 03 6C 6F 6C 00 8C 70 3E EC 72 BD 87
63 EB 29 D2 BB 65 31 23 AC 72 B7 10 63 8E 9D A1
9C 84 4A DC B1 5D 1B D8 22 48 02 D2 95 69 08 52
B7 CD 6B E2 A7 13 FB E0 9A

J'ai tapé lol dans le chat et j'ai envoyé ce paquet.
J'ai retapé lol dans le chat et j'ai envoyé ce paquet (j'ai envoyé plusieurs autres messages pour faire des tests entre)
0D 75 36 00 03 6C 6F 6C 00 46 56 B3 FE 79 3D 7D
32 08 67 85 46 07 27 F4 15 63 F0 94 C1 AE AC 7F
CE F8 B6 52 F3 A2 CB 20 41 2C 87 A3 EA 9E 24 A9
5D FC 0E BF 07 FF 82 12 4A

J'ai pris les 14 premiers bits et j'ai donc eu l'ID du paquet : 861, puis j'ai aussi vu que la taille était encodée sur 1 octet, trés bien.
36 en hexa donne 54 en décimal, j'ai compté pour m'assurer d'avoir juste, 16*2+22= 54, tout va bien.
lol est sur 3 octets si je comprends bien, (6C 6F 6C), et l'octet juste avant sert à annoncer la taille du message (03).

Je comprends jusque là, mais ensuite, ce que je ne comprends pas, c'est pourquoi les 2 paquets sont différents ?

J'ai regardé dans les sources comment était sérialisés et désérialisés les paquets, mais je ne comprends pas
Code:
public function serializeAs_ChatClientMultiMessage(param1:ICustomDataOutput) : void
      {
         super.serializeAs_ChatAbstractClientMessage(param1);
         param1.writeByte(this.channel);
      }
Code:
public function deserializeAs_ChatClientMultiMessage(param1:ICustomDataInput) : void
      {
         super.deserialize(param1);
         this.channel = param1.readByte();
         if(this.channel < 0)
         {
            throw new Error("Forbidden value (" + this.channel + ") on element of ChatClientMultiMessage.channel.");
         }
      }
J'ai jamais fait d'AS auparavant, et je débute la POO, voilà, je ne demande pas à ce qu'on fasse les choses à ma place, mais plutôt à comment comprendre les fonctions de sérialisation et de désérialisation.

Il est possible que j'utilise du vocabulaire de manière maladroite, merci de me le signaler si c'est le cas.
Merci d'avance.
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#2
Hello @chichaaumelon ,

Bravo parce que tu as bien analysé la chose mais tu as oublié un tout petit détails:

Code:
override public function pack(param1:ICustomDataOutput) : void
      {
         var _loc2_:ByteArray = new ByteArray();
         this.serialize(new CustomDataWrapper(_loc2_));
         if(HASH_FUNCTION != null)
         {
            HASH_FUNCTION(_loc2_);
         }
         writePacket(param1,this.getMessageId(),_loc2_);
      }
La condition HASH_FUNCTION qui chiffre le paquet en AES 256.
Tu n'es pas du tout obligé de chiffrer tes paquets, quasiment aucun bot ne le fait, et ça n'a pas l'air d'être un critère de banne.
 
Inscrit
23 Decembre 2016
Messages
6
Reactions
0
#3
Donc tout ce qui est après 6F 6C 6F ne sert à rien ?
Je peux juste envoyer au serveur un paquet 0D 75 05 00 03 6C 6F 6C pour afficher lol dans le chat ?
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#4
La totalité du paquet est chiffré à priori, je ne sais pas exactement comment le serveur gère le chiffrement, je ne sais pas si il prend en compte deux paquets ayant le même chiffrement.

Ce qui est sur c'est que si tu écris les données de la même manière que la fonction Serialize() tu n'auras pas de problème.
 
Inscrit
23 Decembre 2016
Messages
6
Reactions
0
#5
Oui, mais le problème c'est que je ne sais pas comment la fonction serialize() écrit les données. C'est à dire j'ai réussi à comprendre le paquet seulement en en envoyant plusieurs et en faisant des tests avec Wireshark, mais une fois que je suis dans le code source, je ne comprends rien.
 
Inscrit
23 Decembre 2016
Messages
6
Reactions
0
#6
En tout cas, je viens d'envoyer le paquet 0D 75 05 00 03 6C 6F 6C avec WPE, et ça fonctionne, lol s'affiche bien dans le chat.
 

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#7

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#9
Donc tout ce qui est après 6F 6C 6F ne sert à rien ?
Je peux juste envoyer au serveur un paquet 0D 75 05 00 03 6C 6F 6C pour afficher lol dans le chat ?
en fait ce qu'il y'a apres c'est un autre message (genre un ping ou une connerie comme ca) envoyé dans le meme paquet , parfois au lieu d'envoyer 50 petits paquets de 1seul message , le client envoie un seul paquet de 50 messages
le paquet n'est pas du tout chiffré , ca passe pas par
if(HASH_FUNCTION != null)
{
HASH_FUNCTION(_loc2_);
}
parceque HASH_FUNCTION est null
 
Dernière édition:

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#10
@ToOnS Le Hash_Function est initialisé à la réception du RawDataMessage, lors du switch vers le serveur de Jeu, donc je ne pense pas que ce soit nul.

Ah moins que la sécurité soit désactivée ? Mais cela m'étonnerai le code n'a pas changé.
 

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#11
biensure que si il est null , sinon 00 03 6C 6F 6C ca serait pas aussi simple a "traduire de tete" (enfin avec ca : http://www.asciitable.com/index/asciifull.gif , 6C = "l" , 6F = "o" et 6C = "l") , c'est donc pas "chiffré" , on verrait pas 6C 6F 6C dans loc2 , a moins qu'ils aient inventé un chiffrement qui chiffre rien du tout ...
 
Dernière édition:

Arth

Contributeur
Inscrit
28 Aout 2016
Messages
80
Reactions
3
#12
On peut même préciser que AES256 c'est du chiffrage par blocs de 128bits. donc si les données n'ont pas une taille qui est un multiple de 128bit (16octet) elle ne sont pas chiffré.
Les données du message du tchat ne font pas une taille qui est un multiple de 16 octet, donc cela ne correspond pas au résultat d'un chiffrement par AES et en plus comme le dit @ToOnS on voit bien que ce n'est pas du tout chiffré.

Mais si on regarde la suite du message :
Si on néglige le 00 qui sépare les 2 parties du message, on a un bloc qui fait 16*3 octet. donc potentiellement chiffré en AES.
Par contre la fonction s'appel HASH_FUNCTION... AES c'est pas du hachage x) ...
 
Dernière édition:

ToOnS

Membre Actif
Inscrit
8 Avril 2009
Messages
974
Reactions
0
#13
pour qu'on en ai le coeur net , il faudrait sniffer un message dans le chat du genre "ToOnS t'es trop fort" pour depasser les 16 octets et regarder si c'est chiffré ou pas mais je ne le fait pas , ca doit faire 5 ans que j'ai plus dofus dans l'ordi
sinon 00 8C (ID : 35) et 00 46 (ID : 17) ca correspond a rien de connu ? le dernier en effet me semble etrange , ca donnerait une longueur de message de 56 B3 , donc 22 195 octets si ca serait vraiment un autre message , c'est largement plus grand que ce qui a ete sniffé apres (et pour le 1er une longueur de 112 octets , c'est moins flagrand mais c'est pas normal non plus)
 
Dernière édition:

Arth

Contributeur
Inscrit
28 Aout 2016
Messages
80
Reactions
3
#14
@ToOnS
C'est 2 messageId (35 et 17) ne correspondent à rien. Et de toute façon, aucun packet du protocole ne contient un autre packet du protocole. il arrive que des packets soit envoyé ensemble, dans le même packet TCP/IP. Mais le packet length est là pour les séparer et on obtient des packets du protocole du jeu bien séparé.


J'opterais plutôt pour des données anti-bot ajouté au packet. Mais ce message peut être envoyé sans cette sécurité. Donc moi je parierai sur une protection spambot ^^.
Mais la protection est aussi utilisé dans d'autre type de packet.

Donc on peut ce passer de comprendre pour faire un petit bot simple ou en fessant du MITM, mais c'est pas trop ma philosophie de pas chercher à comprendre ^^.
Du coup, il reste à identifier le contenu des données envoyé:
  • la fonction qui construit ces données s'appel HASH_FUNCTION, donc en théorie ce sont des données hashé, des données haché avec le même algo plusieurs fois donne le même résultat, c'est le principe du hachage. Or on constat qu'elle sont différente... il dit y avoir une donnée changeante dans le message haché. Peut-être l'heure, mais cela me semble stupide car cela rend la vérification complexe.. Peut-etre un algo de generation de nombre pseudo aléatoire initialisé par une seed connu par le client et le serveur.
    Si on essai d'identifier la fonction de hachage, on peut regarder la taille des données en sortie, on à 384bit (en négligeant l'octet nul), on regarde dans une liste des algo de hachage connu (ici).. il y a le SHA384, un algo du standard SHA-2, un grand classique. cela semble le plus probable ^^. Mais ils sont capable de nous surprendre x)...
  • Si on suit ce nous dit @BlueDream, cela correspond à des données encoder avec AES. C'est possible. il faudrait utiliser la cle AES pour essayer de décoder les données.
Sinon, si on cherche HASH_FUNCTION dans les sources, la fonction est 'prototypé' mais jamais définit. @BlueDream nous dit qu'elle est définit dans le rawDataMessage.

Donc j'ai une question :
Il y a des gens qui on essayé de décompiler le rawDataMessage pour voir si il n'y a pas des trucs récurant dedans et pour en avoir le coeur net ?
 
Dernière édition par un modérateur:

BlueDream

Administrateur
Membre du personnel
Inscrit
8 Decembre 2012
Messages
2 010
Reactions
149
#15
J'ai longuement étudié le fonctionnement du RawDataMessage, et en effet il y a un système de seed assez complexe qui fait en sorte que les données qui en ressortent ne sont jamais les mêmes.

Bon déjà, voici un RawDataMessage au format SWF, tout frais.
https://mega.nz/#!wANjQC4L!GD-jktwrVDiI1suWxQeIAy1aeoVUTVe2Sw5actvio9U

Le code est très long, plus de 5000 lignes et il est très obfusqué, mais voici la partie qui nous intéresse.
Code:
public function sendTicket() : void
      {
         var _loc18_:* = 0;
         var _loc1_:String = §_a_-_---§.§_a_--_--§(-1820302810);
         if(!ApplicationDomain["currentDomain"]["hasDefinition"](_loc1_))
         {
            return;
         }
         var _loc2_:Object = getDefinitionByName(_loc1_);
         var _loc3_:Class = getDefinitionByName("com.ankamagames.dofus.network.messages.security::CheckIntegrityMessage") as Class;
         var _loc4_:Object = getDefinitionByName(§_a_-_---§.§_a_--_--§(-1820302792));
         var _loc5_:Object = getDefinitionByName(§_a_-_---§.§_a_--_--§(-1820302802));
         var _loc6_:Object = getDefinitionByName(§_a_-_---§.§_a_--_--§(-1820302815));
         var _loc7_:Object = getDefinitionByName(§_a_-_---§.§_a_--_--§(-1820302804));
         var _loc8_:* = new _loc5_(_loc5_["applicationDirectory"]["resolvePath"](§_a_-_---§.§_a_--_--§(-1820302809)));
         var _loc9_:* = new _loc7_();
         var _loc10_:ByteArray = new ByteArray();
         _loc9_["open"](_loc8_,_loc6_["READ"]);
         _loc9_["readBytes"](_loc10_);
         _loc9_["close"]();
         var _loc11_:* = new getDefinitionByName("flash.utils.ByteArray")();
         _loc11_["writeByte"](-55850 - _SEXHLMDMWML(601) ^ this._SEEODGEXOMD);
         _loc11_["writeByte"](16448 - _SEMHDHGWWIH(430) ^ this._SLHIEXOEHL);
         _loc11_["writeByte"](_SEDOEOLOEXH(50) ^ -10691 ^ this._SEIHLIEHGIG);
         _loc11_["writeByte"](_SEMHWILOMXH(311) ^ -16358 ^ this._SEDLODHWMDL);
         _loc11_["writeByte"](148931 - _SEDOEOLOEXH(325) ^ this._SEHWWIEOLOW);
         _loc11_["writeByte"](16360 - _SEMHWILOMXH(643) ^ this._SOGGGWOWDE);
         _loc11_["writeByte"](-54341 - _SEXHLMDMWML(-831) ^ this._SEHWWIEOLOW);
         _loc11_["writeByte"](39716 - _SELXEDMDWIW(401) ^ this._SDEGEIMXWDD);
         _loc11_["writeByte"](_SEXHLMDMWML(743) + 55927 ^ this._SDEDGHOMLOX);
         _loc11_["writeByte"](_SEWGXHIHOE(-359) ^ -162563 ^ this._SEDLODHWMDL);
         _loc11_["writeByte"](_SMHXHOIGEX(-667) + -248773 ^ this._SEEDOXLGMEI);
         _loc11_["writeByte"](-36710 - _SEEXLMLHILE(848) ^ this._SELEDDGHLGM);
         _loc11_["writeByte"](_SMHXHOIGEX(892) ^ -248893 ^ this._SLHIEXOEHL);
         _loc11_["writeByte"](_SEMHWILOMXH(651) ^ -16261 ^ this._SDEGEIMXWDD);
         _loc11_["writeByte"](_SEMHDHGWWIH(-813) ^ -16339 ^ this._SEHWWIEOLOW);
         var _loc12_:_SEIWGELDMLL = new _SEIWGELDMLL();
         var _loc13_:_SEGGHWLLXDH = new _SEGGHWLLXDH(new _SEHLHWHWMOW(new _SOLLHGLEIG(_loc11_),_loc12_));
         var _loc14_:ByteArray = new getDefinitionByName("flash.utils.ByteArray")();
         _loc14_["writeUTF"](_loc2_["getInstance"]()["gameServerTicket"]?_loc2_["getInstance"]()["gameServerTicket"]:"");
         _loc14_["writeBytes"](getDefinitionByName(§_a_-_---§.§_a_--_--§(-1820302803) + "D5")["hash"](_loc10_));
         _loc12_["setBlockSize"](_loc13_["getBlockSize"]());
         _loc13_["decrypt"](_loc14_);
         var _loc15_:Vector.<int> = new Vector.<int>();
         _loc14_["position"] = 0;
         var _loc16_:uint = 0;
         while(_loc14_["bytesAvailable"] != 0)
         {
            _loc18_ = _loc14_["readByte"]();
            _loc15_[_loc16_] = _loc18_;
            _loc16_++;
         }
         getDefinitionByName(§_a_-_---§.§_a_--_--§(-1820302786))["HASH_FUNCTION"] = this.addCryptedHash;
         var _loc17_:* = new _loc3_();
         _loc17_["initCheckIntegrityMessage"](_loc15_);
         _loc4_["getConnection"]()["send"](_loc17_);
      }
C'est cette fonction qui non seulement envoi le paquet CheckIntegrityMessage mais qui définit la valeur de la variable HASH_FUNCTION.
Code:
getDefinitionByName(§_a_-_---§.§_a_--_--§(-1820302786))["HASH_FUNCTION"] = this.addCryptedHash;
Et c'est donc la fonction addCryptedHash qui s'occupe de hasher les données en AES-256.
Code:
public function addCryptedHash(param1:ByteArray) : void
      {
         var _loc5_:Object = null;
         var _loc6_:ByteArray = null;
         if(!this._hashKey)
         {
            _loc5_ = getDefinitionByName(§_a_-_---§.§_a_--_--§(-1820302810));
            _loc6_ = new ByteArray();
            _loc7_["writeUTF"](_loc5_["getInstance"]()["gameServerTicket"]?_loc5_["getInstance"]()["gameServerTicket"]:"");
            this._hashKey = HumanCheck["hash"](_loc6_);
         }
         var _loc2_:ByteArray = new ByteArray();
         _loc2_["writeBytes"](HumanCheck["hash"](param1));
         _loc2_["position"] = 0;
         var _loc3_:_SEIWGELDMLL = new _SEIWGELDMLL();
         var _loc4_:_SEGGHWLLXDH = new _SEGGHWLLXDH(new _SEHLHWHWMOW(new _SOLLHGLEIG(this._hashKey),_loc3_));
         _loc3_["setBlockSize"](_loc4_["getBlockSize"]());
         _loc4_["encrypt"](_loc2_);
         param1["position"] = param1["length"];
         param1["writeBytes"](_loc2_);
      }
J'ai aussi trouvé les sources originales en clair qu'utilise la crypto: (nécessite la dernière maj de flash)
http://crypto.hurlant.com/demo/srcview/
 
Dernière édition:
Inscrit
23 Decembre 2016
Messages
6
Reactions
0
#17
Je up mon topic car je m'étais arrêté d'analyser les paquets 1 ou 2 jours aprés la création du topic pour jouer pendant la fin de vacances, et que je pense que le sujet est à peu près le même.
Enfin bref, je viens de m'y remettre, et après avoir trouvé comment envoyer des messages dans le chat(avec WPE Pro), j'ai décidé de me lancer dans l'analyse du paquet pour se déplacer.

Je vous partage ce que je pense comprendre :
Voila un paquet pour me déplacer de une case vers la droite :

0e d9 3a 00 02 10 cc 10 da 09 2c 07 05 52 97 ea
e3 9d 84 ad bb 8f be 92 2e 28 d3 3f d8 ad 2b 8a
dd ca c9 70 1f d8 2e a7 7b d7 4a c4 e2 5a 61 c1
77 9b 73 22 32 a4 20 1c 74 e9 f8 ad 57

0e d9 : id 950
Taille sur 1 octet : 3a = 59
Je vais dans les sources
Code:
public function deserializeAs_GameMapMovementRequestMessage(param1:ICustomDataInput) : void
      {
         var _loc4_:uint = 0;
         var _loc2_:uint = param1.readUnsignedShort();
         var _loc3_:uint = 0;
         while(_loc3_ < _loc2_)
         {
            _loc4_ = param1.readShort();
            if(_loc4_ < 0)
            {
               throw new Error("Forbidden value (" + _loc4_ + ") on elements of keyMovements.");
            }
            this.keyMovements.push(_loc4_);
            _loc3_++;
         }
         this.mapId = param1.readInt();
         if(this.mapId < 0)
         {
            throw new Error("Forbidden value (" + this.mapId + ") on element of GameMapMovementRequestMessage.mapId.");
         }
      }
Code:
var _loc2_:uint = param1.readUnsignedShort();
Sur 2 octets
00 02 = 2

Code:
while(_loc3_ < _loc2_)
         {
            _loc4_ = param1.readShort();
            if(_loc4_ < 0)
            {
               throw new Error("Forbidden value (" + _loc4_ + ") on elements of keyMovements.");
            }
            this.keyMovements.push(_loc4_);
            _loc3_++;
         }

Code:
_loc4_ = param1.readShort();
2 octets
_loc2_ = 2, la boucle se fera donc deux fois
On lit donc 10 CC cet 10 DA
Je pense que 10 est l'id d'un mouvement vers la droite (même si en général c'est 11 je ne sais pas pourquoi, peut-être que c'est dû à ma position géographique, à certains moment je n'avais pas l'id du mouvement mais l'id-1), j'ai alors trouvé :
Droite : 11
Gauche : 51
Haut : 71
Bas : 31
Diagonale haut droite : 01
Diagonale haut gauche : 61
Diagonale bas droite: 21
Diagonale bas gauche: 41

CC et DA sont les id des cellules ou je me trouve il me semble.
Code:
this.mapId = param1.readInt();
On lit un int, 4 octets
09 2c 07 05 = 153 880 325 C'est l'id de la map

Voila ce que j'ai trouvé, mais maintenant, je me retrouve face à un problème que je n'arrive pas à expliquer :
J'ai renvoyé le paquet au serveur en ayant la même position géographique mais mon perso ne bouge pas, et parfois je me fais même kick du serveur peu après l'envoi du paquet.
Je me demande alors si c'est dû à toute la partie chiffrée qui ne me servait à rien pour les messages publics, ou si il y a un autre élément que je ne vois pas.
 

zahid98

Membre Actif
Inscrit
13 Decembre 2014
Messages
352
Reactions
2
#19
@Labo crois-moi c'est du tout pas surveillé , ce qui est surveillé c'est le temps entre le GameMapMovementRequest et le GameMapMovementConfirm pour eviter les speedHacks...etc , sinon la forme du trajet n'est du tout pas surveillée .
 

Labo

Membre Actif
Inscrit
16 Aout 2013
Messages
799
Reactions
15
#20
Ah oui ? J'ai pas touché à un bot depuis bien trop longtemps alors, mais avant si on avait pas le même A* on se faisait ban…
 
Haut Bas